Comprendre les différences de motivations:
Supposons que vous construisez un outil où vous avez des objets et une implémentation concrète des interrelations des objets. Puisque vous prévoyez des variations dans les objets, vous avez créé une indirection en assignant la responsabilité de créer des variantes des objets à un autre objet ( nous l'appelons usine abstraite ). Cette abstraction trouve un avantage important car vous prévoyez de futures extensions nécessitant des variantes de ces objets.
Une autre motivation assez intrigante dans cette ligne de pensée est un cas où tout ou partie des objets de l'ensemble du groupe auront une variante correspondante. En fonction de certaines conditions, l'une ou l'autre des variantes sera utilisée et dans chaque cas, tous les objets doivent être de la même variante. Cela peut être un peu contre-intuitif à comprendre car nous avons souvent tendance à penser que - tant que les variantes d'un objet suivent un contrat uniforme commun ( interface au sens large) ), le code d'implémentation concret ne doit jamais se casser. Le fait fascinant ici est que, ce n'est pas toujours le cas, en particulier lorsque le comportement attendu ne peut pas être modélisé par un contrat de programmation.
Un simple ( emprunt de l'idée au GoF ) est toute application graphique, par exemple un moniteur virtuel qui émule l'apparence de MS ou Mac ou Fedora OS. Ici, par exemple, lorsque tous les objets widget tels que fenêtre, bouton, etc. ont une variante MS à l'exception d'une barre de défilement dérivée de la variante MAC, le but de l'outil échoue gravement.
Ces cas ci-dessus forment le besoin fondamental de Abstract Factory Pattern .
D'un autre côté, imaginez que vous écrivez un framework afin que de nombreuses personnes puissent construire différents outils ( comme celui des exemples ci-dessus ) en utilisant votre framework. Par l'idée même d'un framework, vous n'en avez pas besoin, bien que vous ne puissiez pas utiliser des objets concrets dans votre logique. Vous mettez plutôt des contrats de haut niveau entre divers objets et comment ils interagissent. Alors que vous (en tant que développeur de framework ) restez à un niveau très abstrait, chaque constructeur de l'outil est obligé de suivre vos constructions de framework. Cependant, ils ( les constructeurs d'outils ) ont la liberté de décider quel objet à construire et comment tous les objets qu'ils créent interagiront. Contrairement au cas précédent ( de Abstract Factory Pattern ), vous (en tant que créateur de framework) n'ont pas besoin de travailler avec des objets concrets dans ce cas; et peut plutôt rester au niveau du contrat des objets. De plus, contrairement à la deuxième partie des motivations précédentes, vous ou les constructeurs d'outils n'avez jamais de situations de mélange d'objets de variantes. Ici, alors que le code cadre reste au niveau du contrat, chaque constructeur d'outils est limité ( par la nature du cas lui-même ) à utiliser ses propres objets. Les créations d'objets dans ce cas sont déléguées à chaque implémenteur et les fournisseurs de framework fournissent simplement des méthodes uniformes pour créer et renvoyer des objets. De telles méthodes sont inévitables pour le développeur de framework pour continuer avec leur code et ont un nom spécial appelé méthode Factory ( Factory Method Pattern pour le modèle sous-jacent ).
Quelques notes:
- Si vous êtes familier avec la `` méthode de modèle '', alors vous verriez que les méthodes d'usine sont souvent invoquées à partir de méthodes de modèle dans le cas de programmes appartenant à n'importe quelle forme de cadre. En revanche, les méthodes de modèle de programmes d'application sont souvent une implémentation simple d'un algorithme spécifique et sans méthodes d'usine.
- En outre, pour l'intégralité des pensées, en utilisant le cadre ( mentionné ci-dessus ), lorsqu'un constructeur d'outils construit un outil, à l'intérieur de chaque méthode d'usine, au lieu de créer un objet concret, il / elle peut déléguer davantage la responsabilité à un résumé -objet d'usine, à condition que le constructeur d'outils prévoit des variations des objets concrets pour de futures extensions.
Exemple de code:
//Part of framework-code
BoardGame {
Board createBoard() //factory method. Default implementation can be provided as well
Piece createPiece() //factory method
startGame(){ //template method
Board borad = createBoard()
Piece piece = createPiece()
initState(board, piece)
}
}
//Part of Tool-builder code
Ludo inherits BoardGame {
Board createBoard(){ //overriding of factory method
//Option A: return new LudoBoard() //Lodu knows object creation
//Option B: return LudoFactory.createBoard() //Lodu asks AbstractFacory
}
….
}
//Part of Tool-builder code
Chess inherits BoardGame {
Board createBoard(){ //overriding of factory method
//return a Chess board
}
….
}