IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage PHP Discussion :

[MVC] Ajouter des fonctionnalités au modèle


Sujet :

Langage PHP

  1. #1
    Membre averti

    Profil pro
    Inscrit en
    Mai 2002
    Messages
    638
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 638
    Points : 408
    Points
    408
    Par défaut [MVC] Ajouter des fonctionnalités au modèle
    Bonjour,
    Dans mon framework PHP, je dispose d'une classe Model simple, qui sert de base à tous mes modèles :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    abstract class Model {
     
    	public function save() {
    		/* Sauvegarde les données en base */
    	}
     
    	public function delete() {
    		/* Supprime les données en base */
    	}
     
    }
    Je voudrais ajouter des fonctionnalités à mes modèles, de manière optionnelle et en réutilisant mon code.
    Mon idée est d'utiliser le pattern Decorator.

    Je définis une classe Decorator abstraite :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    abstract class Decorator {
    	$protected $model;
     
    	public function __construct( $model ) {
    		$this->model = $model;
    	}
     
    	public function __call( $method, $args ) {
    		return call_user_func_array( array( get_class( $this->model ), $method), $args );
    	}
    }
    J'aurais par exemple un Decorator permettant de gérer un modèle multilingue, en ajoutant simplement un suffixe (_en, _fr) aux noms des champs.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    class TranslateDecorator extends Decorator {
     
    	public $language;
    	public $translated;
     
    	public function __construct() {
    		parent::__construct();
    		if ( !empty( $_SESSION['language'] ) ) {
    			$this->language = $_SESSION['language'];
    		}
    	}
     
    	public function __set( $name, $value ) {
    		if ( in_array( $name, $this->translated ) ) {
    			$name .= '_' . $this->language;
    		}
    		$this->model->name = $value;
    	}
     
    }
    Ou Decorator permettant de gérer une corbeille :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    class TrashDecorator extends Decorator {
     
    	/* Surcharge de delete() */
    	public function delete() {
    		$this->model->is_deleted = 1;
    		$this->model->save();
    	}
     
    	public function unDelete() {
    		$this->model->is_deleted = 0;
    		$this->model->save();
    	}
     
    	public function emptyTrash() {
    		foreach ( $this->model->findAll() as $model ) {
    			$model->delete();
    		}
    	}
    }
    Je définis mes modèles :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    class ArticleModel extends Model {
    	// Définition de la classe
    }
    Ensuite je peux instancier mon modèle et ajouter mes decorators :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    $article = new TrashDecorator( new TranslateDecorator( new ArticleModel ) );
    $article->translated = array( 'title', 'text' );
    $article->language = 'fr';
     
    $article = $article->findOne( 4 );
    $article->title = 'Mon titre';
    $article->save();
     
    $article->delete();
    $article->emptyTrash();
    Je trouve ce système efficace, simple et élégant.

    Que pensez-vous de cette approche ?

  2. #2
    Membre éclairé
    Avatar de bricecol
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Avril 2007
    Messages
    364
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Consultant informatique

    Informations forums :
    Inscription : Avril 2007
    Messages : 364
    Points : 654
    Points
    654
    Par défaut
    et bien personnellement, je trouve çà très bien.
    tu utilises bien les notions autour des objets.
    "Computers are like Old Testament gods ; Lots of rules and no mercy"
    [ Les ordinateurs sont comme les dieux de l’Ancien testament ; Beaucoup de règles et aucune pitié. ] Joseph Campbell

  3. #3
    Membre éclairé Avatar de metagoto
    Profil pro
    Hobbyist programmateur
    Inscrit en
    Juin 2009
    Messages
    646
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Hobbyist programmateur

    Informations forums :
    Inscription : Juin 2009
    Messages : 646
    Points : 845
    Points
    845
    Par défaut
    Je me pose la question:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $article = $article->findOne( 4 );
    Juste avant ce code, $article était un TrashDecorator.
    Que retourne findOne() ? Une nouvelle instance ? Dans ce cas quel est son type ?
    Si findOne() se contente juste de modifier $this (donc ne pas créer de nouvelle instance), il va falloir je pense mettre en place un mécanisme assez complexe pour répercuter dans la chaîne de décorators le fait qu'il y ait un changement d'état parce que findOne() est probablement définie dans la classe Model.

    Il faudrait que Model et Decorator implémentent une interface commune (genre IModel) pour que tu ne sois pas embêter par des questions de type hinting.

    N'hésite pas à clarifier les choses si je me suis trompé. C'est un post intéressant

  4. #4
    Membre averti

    Profil pro
    Inscrit en
    Mai 2002
    Messages
    638
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 638
    Points : 408
    Points
    408
    Par défaut
    Citation Envoyé par metagoto Voir le message
    Juste avant ce code, $article était un TrashDecorator.
    Que retourne findOne() ? Une nouvelle instance ? Dans ce cas quel est son type ?
    Si findOne() se contente juste de modifier $this (donc ne pas créer de nouvelle instance), il va falloir je pense mettre en place un mécanisme assez complexe pour répercuter dans la chaîne de décorators le fait qu'il y ait un changement d'état parce que findOne() est probablement définie dans la classe Model.
    Merci de ta réponse.

    En effet cela pose un problème.
    Pour l’instant findOne() crée une nouvelle instance. Je pourrais le modifier pour retourner $this. Cela devrait fonctionner car les decorators ne font que surcharger ou ajouter des méthodes. A première vue le changement d’état ne pose donc pas trop de problème. Mais je me trompe peut-être…

    Par contre ma classe Model dispose d’une méthode findAll() quil retourne instancie une liste d’objets et retourne un tableau.

    J’ai étudié différentes possibilités mais je n’ai rien trouvé de très satisfaisant.
    J’ai pensé à utiliser une Factory pour instancier mes modèles. La liste des decorators à appliquer serait stockée quelque part. De cette manière on instancierait toujours un objet convenablement décoré. Mais cela ne permet de pas répercuter un changement d’état d’un décorateur effectué avant la création des nouveaux objets.

    Autre possibilité : La classe Model pourrait implémenter l’interface Iterator, de manière à ce qu’on puisse le parcourir comme un tableau. Dans ce cas ma méthode findAll() retournerait simplement $this et non plus un tableau après avoir instancié de nouveaux objets.

    Mais il y a certainement d’autres approches auxquelles je n’ai pas pensé.

  5. #5
    Membre éclairé Avatar de metagoto
    Profil pro
    Hobbyist programmateur
    Inscrit en
    Juin 2009
    Messages
    646
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Hobbyist programmateur

    Informations forums :
    Inscription : Juin 2009
    Messages : 646
    Points : 845
    Points
    845
    Par défaut
    Notre échange me conforte dans mon idée qu'une approche Decorator n'est pas judicieuse. En revanche, un truc à base de subjects/observers me paraît plus intéressante.

    Voici un code à l'arrache (pour php 5.3 uniquement) qui esquisse une solution:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    // pour le type hinting (passage de Models à des fonctions)
    interface IModel
    {
      public function save(); 
      public function delete();
      //...
    }
     
     
    // subjects/observers mechanics
    abstract class ModelBase implements SplSubject
    {
      private $observers;
     
      public function __construct()
      {
        $this->observers = new SplObjectStorage;
      }
     
      public function attach(SplObserver $o)
      {
        $this->observers->attach($o);
      }
     
      public function detach(SplObserver $o)
      {
        $this->observers->detach($o);
      }
     
      public function notify($key = null)
      {
        foreach ($this->observers as $o) {
          /*$res = */$o->update($this, $key); // si besoins d'un retour
        }
      } 
    }
     
     
    abstract class Model extends ModelBase implements IModel
    {
      public function save()
      {
        $this->notify("save");   
        // reste du save() si ok 
      }
     
      public function delete()
      {
        $this->notify("delete");    
        // ...
      }
     
     
      // static members
      public static function findOne($id)
      {
        $class = get_called_class(); // "Late Static Binding" class name
        // utiliser un query builder pour construire $class
        return new $class;
      }
     
      public static function findAll($specialClause = null)
      {
        // même chose que findOne()
        // retourner un array de $class 
      }
     
    }
     
     
    // quelques observers
    class TrashObserver implements SplObserver
    {
      public function update(SplSubject $subject, $key = null)
      {
        echo $key;
        var_dump($subject);  
        //return true; // si besoins d'un retour
      }
    }
     
    class TranslateObserver implements SplObserver
    {
      public function update(SplSubject $subject, $key = null)
      {
        echo $key;
        var_dump($subject);  
      }
    }
     
     
    // on définit ici le comportement des Articles
    abstract class ArticleBase extends Model
    {
      public function __construct()
      {
        parent::__construct();
        $this->attach(new TrashObserver);
        $this->attach(new TranslateObserver);
      }
     
    }
     
    class Article extends ArticleBase
    {
      // high level custom stuff (au cas où) 
    }
     
    $article = new Article;
    $article->save();
     
    $article2 = Article::findOne(3);
    $article2->delete();

  6. #6
    Membre averti

    Profil pro
    Inscrit en
    Mai 2002
    Messages
    638
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 638
    Points : 408
    Points
    408
    Par défaut
    En fait j'avais envisagé d'utiliser le motif Observateur mais pour une autre problématique : avoir un couplage faible entre modules.
    En effet ça semble une solution très intéressante. Je vais explorer cette idée.

    Cependant je n'abandonne pas complètement l'idée du Decorator.

    Que penses-tu du système suivant :
    La méthode findAll() retourne un itérateur (Je n'utilise pas le late static binding car je suis encore en PHP 5.2.). La méthode findOne retourne $this.
    Un Decorateur peut être appliqué soit directement à un modèle, soit à un intérateur (implémentant l'interface itérateur).
    Dans ce cas le code suivant fonctionne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    $article = new TrashDecorator( new TranslateDecorator( new ArticleModel() ) );
    $article = $article->findOne( 4 );
    /* findOne( 4 ) retourne $this */
    $article->translated = array( 'title', 'text' );
    $article->language = 'fr';
    $article->title = 'Mon titre';
    $article->save();
     
    $article->delete();
    $article->emptyTrash();
     
    $articles = new ArticleModel();
    $articles = $articles->findAll();
    $articles = new TrashDecorator( new TranslateDecorator( $articles ) );
    $articles->translated = array( 'title', 'text' );
    $articles->language = 'fr';
     
    foreach ( $articles as $article ) {
    	echo $articles->title;
    }
    Ou mieux : La classe Model peut elle-même se comporter comme un itérateur.
    Dans ce cas findAll() retourne $this et le code suivant fonctionne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    $articles = new TrashDecorator( new TranslateDecorator( new ArticleModel() ) );
    $articles = $articles->findAll();
    $articles->translated = array( 'title', 'text' );
    $articles->language = 'fr';
     
    foreach ( $articles as $article ) {
    	echo $articles->title;
    }

  7. #7
    Membre averti

    Profil pro
    Inscrit en
    Mai 2002
    Messages
    638
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 638
    Points : 408
    Points
    408
    Par défaut
    Si j'utilise le système d'observateurs, je dois utiliser __call() dans le modèle et une boucle sur les observateurs pour appeler leurs méthodes (emptyTrash()...).
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    public function __call( $method, $args ) {
    	foreach ( $this->observers as $o ) {
    	if ( method_exists( $observer, $name )) {
    		array_unshift( $args, $this );
    		return call_user_func( array( $observer, $name ), $args );
    	}
    }
    Je fais hériter mes observateurs d'une classe abstraite :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    abstract class Observer implements SplObserver {
    	public function update( SplSubject $subject, $key = null ) {
    		$this->model = $subject;
    		return $this->$key();
    	}
    }
    class TrashObserver extends Observer {
     
    	public function delete() {
    		$this->model->is_delete = true;
    		$this->model->save();
    		return false;
    	}
     
    	public function emptyTrash( $model ) {
    	 	foreach ( $this->model->findAll() as $model ) {
    			$model->delete();
    		} 
    	 }
    }

  8. #8
    Membre éclairé Avatar de metagoto
    Profil pro
    Hobbyist programmateur
    Inscrit en
    Juin 2009
    Messages
    646
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Hobbyist programmateur

    Informations forums :
    Inscription : Juin 2009
    Messages : 646
    Points : 845
    Points
    845
    Par défaut
    Je ne suis toujours pas convaincu par un design avec decorators. Même si on pourrait probablement imaginer une voie détournée pour simplifier ce genre d'écriture:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $article = new TrashDecorator( new TranslateDecorator( new ArticleModel() ) );
    ... je pense toujours que ça va créer plus de problèmes que ça ne va en résoudre. En partie parce que dans les exemples présentés, il va falloir se trimbaler "new TrashDecorator( new TranslateDecorator(" dès qu'on manipule un article. Et en partie aussi à cause de ceci:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $article = $article->findOne( 4 );
    Dans le context qui est le notre, nos objets du model ont théoriquement une sémantique d'unicité très forte (orm). Or retourner un $this modifié comme présenté juste au dessus est une abération (en ce qui me concerne ).
    Je pense que ce n'est pas pour rien que dans la plupart des orm existants, on passe par une classe spécialisée (qui peut encapsuler une table par exemple) ou des méthodes statiques pour rapatrier ou créer de nouveaux objets. C'est le cas dans Propel ou Doctrine et d'autres. D'ailleurs, Doctrine fonctionne avec un mécanisme d'observers (entre autres).

    Une fois qu'un objet du model est créé, il ne devrait jamais changer (dans le sens, modéliser une autre entité de la db, souvent un row). L'objet peut être référencé à plusieurs endroits différents d'un code php et si on le modifie radicalement à un endroit, ça aura des répercussions généralement non voulues ailleurs. Et là je ne considère même pas le fait qu'un objet puisse être transformé en un groupement d'objets avec findAll().

    Il y a toujours l'option du clonage (clone en php), mais l'architecture à base de decorators ne s'y prête pas bien.

    Mon point de vue est forgé par une vision très orm du problème. Finalement je me dis que ce n'est probablement pas tout à fait ce que tu souhaites faire.
    Par exemple le concepte d'EmptyTrash, dans un cadre orm, ça ne devrait pas être une propriété de chaque entité du model, mais plutôt un truc "haut dessus". Une facilité pour manipuler un groupement d'objets. Les observers dans mon premiers posts n'auraient d'intéret que pour effectuer des opérations sur l'instance unique à laquelle ils sont rattachés (par exemple vérifier un bon format des données avant d'être sauvegardé en table, ou déclencher des opérations annexes (invalider du cache, logger, vérifier des droits etc)).

  9. #9
    Membre averti

    Profil pro
    Inscrit en
    Mai 2002
    Messages
    638
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 638
    Points : 408
    Points
    408
    Par défaut
    Citation Envoyé par metagoto Voir le message
    Une fois qu'un objet du model est créé, il ne devrait jamais changer (dans le sens, modéliser une autre entité de la db, souvent un row). L'objet peut être référencé à plusieurs endroits différents d'un code php et si on le modifie radicalement à un endroit, ça aura des répercussions généralement non voulues ailleurs. Et là je ne considère même pas le fait qu'un objet puisse être transformé en un groupement d'objets avec findAll().
    Je pense que tu as raison. findOne() et findAll() ne doivent pas retourner $this mais bien instancier de nouveaux objets. En fait j’emploie la syntaxe :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    $article = $article->findOne( 4 );
    $articles = $articles->findAll() ;
    à la place de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    $article = ArticleModel::findOne( 4 );
    $articles = ArticleModel::findAll() ;
    qui ne fonctionne qu’en PHP 5.3.
    Je devrais peut-être avoir des noms de variables différents pour que ce soit plus clair.

    Citation Envoyé par metagoto Voir le message
    Mon point de vue est forgé par une vision très orm du problème. Finalement je me dis que ce n'est probablement pas tout à fait ce que tu souhaites faire.
    Par exemple le concepte d'EmptyTrash, dans un cadre orm, ça ne devrait pas être une propriété de chaque entité du model, mais plutôt un truc "haut dessus". Une facilité pour manipuler un groupement d'objets.
    C’est ce que je veux faire. Mais je m’autorise certains écarts pour gagner en simplicité et éviter de multiplier les classes. ArticleModel représente un article. Mais elle contient également des méthodes concernant la gestion des articles. Ces méthodes devraient être statiques mais ce n’est pas possible sans le late satic binding de PHP 5.3.

    J’oublie les Decorators qui ne sont pas adaptés.

    Pour résumer, je voudrais ajouter des fonctionnalités à mes modèles de trois façons différentes :
    • Effectuer des traitements et modifier l’état de l’objet lors d’événements précis. Pour cela le système d’observateurs convient parfaitement.
    • Mettre à disposition des méthodes supplémentaires, qu’il s’agisse de modifier l’état de l’objet ou bien d’effectuer des actions sur un ensemble d’objets (unDelete(), emptyTrash()…).
    • Surcharger des méthodes de base (ex. surcharge de delete()).

    Je vais implémenter un système d'observateurs, peut-être accompagné par un système de mixins.

  10. #10
    Membre averti

    Profil pro
    Inscrit en
    Mai 2002
    Messages
    638
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 638
    Points : 408
    Points
    408
    Par défaut
    Pas d'autres remarques ou suggestion sur ces approches ?

  11. #11
    Membre averti

    Profil pro
    Inscrit en
    Mai 2002
    Messages
    638
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 638
    Points : 408
    Points
    408
    Par défaut
    J'ai ajouté un système d'événements (base sur SplSubject/SplObserver), qui s'avère très utile. Néanmoins il ne répond pas complètement au problème initial car il ne permet pas d'ajouter de nouvelles reponsabilités (de nouvelles méthodes) à une classe. J'en reviens donc aux décorateurs. En effet je trouve que le décorateur est une solution très puissante et élégante pour étendre des classes.

    Le problème est de pouvoir créer mes classes de modèles avec les décorateurs adéquats.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    $article = Article::findOne( 7 );
    $articles = Article::findAll();
    Mon idée est d'utiliser une factory qui permettrait d'instancier un modèle décoré de manière adéquate, à partir d'un fichier de configuration.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    class Model {
        public static function findOne() {
        // Exécution de la requête SQL
     
        // Création de l'instance du modèle
        $model = Factory::create( $className );
     
        /* Au lieu de :
        $model = new $className(); */
    }
     
    class Factory {
        public static function create( $className ) {
            // Récupération de la liste des décorateurs à partir d'un fichier de configuration.
     
            $object = new $className();
            foreach( $decorators as $decorator ) {
                $object = new $decorator( $object );
            }
    }
    Intérêt de cette approche :
    • Je peux étendre facilement mes modèles via des décorateurs/proxies.
    • Les finders de la classe Model ne sont quasiment pas modifiés.
    • Toutes mes instances de modèles retournées sont décorées.

  12. #12
    Membre éclairé Avatar de metagoto
    Profil pro
    Hobbyist programmateur
    Inscrit en
    Juin 2009
    Messages
    646
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Hobbyist programmateur

    Informations forums :
    Inscription : Juin 2009
    Messages : 646
    Points : 845
    Points
    845
    Par défaut
    Un factory similaire qui attache des custom observers au runtime (ton fichier de config) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    $object = new $className();
    foreach( $decorators as $decorator ) {
      $object->attach($decorator);
    }
    Ensuite, il faudrait définir __call() dans la class Model (je reprends mon exemple plus haut) pour que tout ce qui arrive à __call soit forwardé en notify pour les observers que ça intéressent.

    J'ai pas trop réfléchis, juste parcouru nos précédents échanges, mais à première vue, je serai toujours plutôt penché sur une archi à base d'observers

  13. #13
    Membre averti

    Profil pro
    Inscrit en
    Mai 2002
    Messages
    638
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 638
    Points : 408
    Points
    408
    Par défaut
    Ensuite, il faudrait définir __call() dans la class Model (je reprends mon exemple plus haut) pour que tout ce qui arrive à __call soit forwardé en notify pour les observers que ça intéressent.
    Effectivement, en modifiant les méthodes notify() et update() pour transmettre des arguments supplémentaires cela permet de résoudre le problème, de manière bien plus élégante.

Discussions similaires

  1. Réponses: 7
    Dernier message: 13/07/2010, 14h33
  2. [C# 2.0] Ajouter des fonctionnalités au MonthCalandar
    Par margagn dans le forum Windows Forms
    Réponses: 2
    Dernier message: 01/08/2006, 17h11

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo