Template Method Design Pattern
But Définir le squelette d’un algorithme tout en déléguant certaines étapes aux sous-classes. Les sous-classes peuvent redéfinir certaines étapes de l’algorithme sans en changer la structure.
Exemple public class Application {…public OpenDocument (String name) { if (!CanOpenDocument(name)) { // cannot handle this document return; } Document doc =DoCreateDocument(); if (doc != null) { _docs.AddDocument(doc); AboutToOpenDocument(doc); doc.Open(); doc.DoRead(); } } }
Exemple La méthode template définit l’algorithme en termes d’opérations abstraites. Les sous-classes les redéfinissent pour spécifier le comportement concret de différentes étapes de l’algorithme Est-ce que le document peut être ouvert? (CanOpenDocument) Création du document (DoCreateDocument) Lecture du document (DoRead). Informer les sous-classes que le document va être ouvert au cas où elles s’en préoccuperaient (AboutToOpenDocument). La méthode “template” fixe l’ordre des opérations, mais laisse la possibilité aux sous-classes de définir les détails de ces opérations.
Quand appliquer le patron Template Method? Pour implémenter les parties invariantes d’un algorithme une seule fois et laisser aux sous-classes le soin d’implémenter les parties qui varient. Lorsqu’un comportement commun entre des sous-classes devrait être factorisé et placé dans une classe commune afin d’éviter la duplication de code "refactoring to generalize" Identifer les différences dans le code existant Extraire ces différences dans de nouvelles méthodes Utiliser le template method pour appeler ces méthodes Pour contrôler les extensions des sous-classes Définir une méthode template qui appelle des méthodes "hook" en des points spécifiques de manière à ne permettre les extensions seulement qu’en ces points
Structure
Participants AbstractClass ( Application ) Définit les méthodes abstraites de base que les sous-classes doivent implémenter pour les diverses étapes de l’algorithme. Implémente la méthode “template” qui définit le squelette de l’algorithme. Cette méthode invoque aussi bien les méthodes abstraites que les méthodes définies dans AbstractClass ou celles de d’autres objets. ConcreteClass ( MyApplication ) Implémente les opérations abstraites pour réaliser les étapes spécifiques aux sous-classes
Collaborations entre les classes ConcreteClass repose sur AbstractClass pour l’implémentation des étapes invariantes de l’algorithme
Exemple
Exemple : refactorisation Classe abstraite public abstract class TextDocument { … public final void printPage(Page page) { printTextHeader(); printTextBody(page); printTextFooter(); } protected abstract void printTextHeader(); protected final void printTextBody(Page page) { System.out.println(page.body()); } protected abstract void printTextFooter(); … }
Exemple : Refactorisation Sous-classes
Conséquences I Une technique fondamentale pour la réutilisation du code Particulièrement importante dans les librairies de classes Le moyen pour factoriser les comportements communs Une structure de contrôle inversée "the Hollywood principle," that is, "Don't call us, we'll call you" La classe parent appelle les méthodes des sous-classes et non l’inverse. Un template method invoque en général les types de méthodes suivants: Méthodes concrètes de ConcreteClass ou de classes clients; Méthodes concrètes de AbstractClass Méthodes abstraites factory methods Méthodes “hook”, Comportement par défaut que les sous-classes peuvent redéfinir Souvent ces méthodes sont vides. Afin de bien réutiliser une classe abstraite, il faut bien identifier Les méthodes “hook” qui peuvent être redéfinies Les méthodes abstraites qui doivent être redéfinies.
Conséquences II Une sous-classe peut spécialiser une méthode d’une classe parent en redéfinissant cette méthode et en invoquant la méthode de la superclasse explicitement Public class DerivedClass extends ParentClass { public void operation () {super.operation(); } } Cependant, il facile d’oublier l’invocation de la méthode de la superclasse Transformation en méthode “template” pour donner le contrôle à la classe parent La classe parent définit une méthode hook que les sous-classe peuvent redéfinir Public class ParentClass { “final” public void operation () {HookOperation(); } pubic void hookOperation () { } }} Les sous-classes redéfinissent HookOperation : Public class DerivedClass extends ParentClass { public void hookOperation () { // DerivedClass extended behavior }
Implémentation Méthodes abstract, protected, final Minimiser les méthodes abstraites. Plus il y aura de méthodes à définir, plus ce sera fastidieux Définir des conventions au niveau des noms. Par exemple, pour définir les méthodes qui devraient être redéfinies, utiliser un préfixe. Dans le MacApp framework pour les applications Macintosh Le nom des méthodes relative à un template method commencent avec "Do-“ "DoCreateDocument", "DoRead", etc.
Design Patterns reliés Factory Methods souvent appelés par les template methods la méthode DoCreateDocument de la méthode OpenDocument de l’exemple. Strategy Les méthodes Template utilisent l’héritage pour faire varier des parties d’un algorithme Les stratégies utilisent la délégation pour faire varier tout l’algorithme.
Références William F. Opdyke and Ralph E. Johnson. Creating abstract superclasses by refactoring. In Proceedings of the 21st Annual Computer Science Conference (ACM CSC '93), pages 66–73, Indianapolis, IN, February 1993 Creating abstract superclasses by refactoring Rebecca Wirfs-Brock and Ralph E. Johnson. A survey of current research in object-oriented design. Communications of the ACM, 33(9):104–124, 1990A survey of current research in object-oriented design