P
'
t
i
t
e
C
h
a
t
t
e
 
spacer~ ALWAYS REMEMBER YOU'RE UNIQUE, JUST LIKE EVERYONE ELSE Articles | Connexion
 
~Template et visiteur

 Présentation

Au menu cette fois-ci, deux nouveaux motifs de conception, tout chauds et prêts à l'emploi. Les deux motifs de conception sélectionnés pour ce cours appartiennent tous deux au groupe de motifs comportementaux. Ceux-ci s'intitulent Template (ou Patron de méthode) et Visiteur.
 Sommaire


 Le motif Template

Le principe du Patron de méthode consiste en la création d'une classe mère dont l'implémentation d'une ou plusieurs méthodes se voit confiée aux classes dérivées. Le motif Template formalise ainsi l'idée de définir un algorithme sous forme d'une classe. Toutefois, la réalisation de certains détails appartient aux enfants. Cet aspect octroie l'opportunité de spécialiser des parties de l'algorithme. En d'autres termes, lorsque votre classe parente se trouve abstraite (mot-clé abstract en Java par exemple), vous avez recours à une forme simplifiée du motif Template.

L'idée sous-jacente à la théorie du motif Template réside dans l'idée qu'un algorithme puisse posséder des bases solides bien définies tandis que certaines parties peuvent posséder diverses implémentations. Un autre signe distinctif des motifs Template consiste en la factorisation de certaines fonctionnalités au sein de la classe mère. Nous pouvons penser à une classe mère représentant un axe de dessin orthonormé. Des méthodes factorisées se verraient incarnées par des méthodes de calculs de coordonnées. Typiquement, un Template connaît quatre sortes de méthodes dont vous pouvez faire usage dans une classe dérivée :
  • Des méthodes complètes, appelées méthodes concrètes, offrant des services que toutes les sous-classes seront susceptibles d'employer.
  • Des méthodes laissées intégralement aux bons soins des classes dérivées. Nous rencontrons ici les méthodes abstraites (que nous opposons donc au type de méthodes précédent).
  • Des méthodes contenant une implémentation par défaut pouvant se voir surchargée au coeur des classes filles. De telles méthodes sont désignées sous le terme de hooks.
  • Des méthodes appelant une combinaison quelconque des trois sortes précédentes. Ces méthodes ne sont pas appelées à se voir surchargées, mais définissent un algorithme au fonctionnement dépendant des classes filles.

Notre exemple se base sur un tri simple. La classe mère Sorter propose une méthode sort(liste) pouvant se spécialiser lors de la comparaison des éléments de la liste à trier. Nous pouvons en effet demander un tri normal, ou un tri inversé. Nous laisserons ce travail aux soins des classes dérivées. Le listing suivant présente la définition de la classe Sorter en Python :

class Sorter:
    def sort(self, list):
        for i in range(len(list) - 1):
            for j in range(i, len(list)):
                if self.compareItems(list[i], list[j]):
                    list[i], list[j] = list[j], list[i]
    def getName(self):
        return "Trieur de liste"
    def getDescription(self):
         pass
    def compareItems(self, item1, item2):
        pass
       
      
JextCopier dans Jext | Jext | Plugin Codegeek
Les méthodes compareItems() et getDescription() constituent des méthodes abstraites. La méthode getName() incarne un hook. La mise en place définitive de notre motif de conception nécessite l'héritage de la classe Sorter. Le listing suivant présente la réalisation d'une classe permettant un tri inversé :

class DescendantSorter(Sorter):
    def compareItems(self, item1, item2):
        return item1 <= item2
    def getDescription(self):
        return "Tri par ordre inverse"
       
      
JextCopier dans Jext
L'algorithme essentiel du tri placé dans Sorter pourra ainsi se voir aisément spécialisé. Reportez-vous au fichier sorter.py présent dans le fichier zip en annexe pour examiner un exemple complet du motif.


 Le motif Visiteur



A défaut d'envahisseurs, découvrez les visiteurs.

Le motif Visiteur déroge à quelques règles et semble aller à l'encontre des principes fondamentaux de la programmation orientée objet. Le principe du motif Visiteur consiste à réaliser une classe agissant sur les données issues d'autres classes. Imaginons un ensemble de classes dérivées d'une classe mère, chacune implémentant une méthode draw(). Le principe du Visiteur va consister à déplacer toutes les méthodes draw() dans le Visiteur pour ne pas dupliquer de code entre les différentes classes.

La réalisation d'une opération de visite se déroule suivant un protocole particulier. Chaque classe susceptible de se voir visitée doit contenir une méthode intitulée accept(Visitor v). Le code de cette méthode exécutera en retour l'instruction v.visit(this) pour signifier au Visiteur qu'il possède le droit de venir voir ce qu'il se passe dans cette classe.



Modélisation du processus de visite.

L'emploi du motif Visiteur trouve son intérêt lorsque vous souhaitez appliquer une opération sur les données de plusieurs objets dont les interfaces se veulent différentes. Le Visiteur s'utilise également pour pratiquer des opérations sans aucun rapport entre elles. Toutefois, l'application de ce motif ne se révèle pas des plus judicieuses lorsque vous savez que votre programme sera amené à intégrer de nouvelles classes pouvant prendre place au cour des opérations du Visiteur.

Notre exemple repose sur le calcul de la somme des surfaces et des périmètres d'un ensemble hétérogène d'objets, composé de cercles et de rectangle. Ces derniers dérivent de la classe mère Shape qui n'offre que les coordonnées des objets. Aucune de ces classes ne comprend de méthode pour calculer la surface ou le périmètre. En revanche, elles s'avèrent aptes à délivrer les informations nécessaires à ces calculs. Ce listing présente le code source de la classe Circle en C# :

public class Circle: Shape
{
  protected int radius;
  public Circle(int x, int y, int radius): base(x, y)
  {
    this.radius = radius;
  }
  public int Radius
  {
    get { return radius; }
  }
  public void accept(Visitor v) { v.visit(this); }
}
       
      
JextCopier dans Jext | Jext | Plugin Codegeek
Constatez la présence de la fameuse méthode visit(). Nos deux classes Circle et Rectangle définies, nous pouvons nous pencher à présent sur la définition abstraite d'un Visiteur. Puisque celui-ci devra gérer des cercles et des rectangles, nous devons le pourvoir de deux méthodes abstraites :

public abstract class Visitor
{
  public abstract void visit(Circle c);
  public abstract void visit(Rectangle r);
}
       
      
JextCopier dans Jext
Dorénavant, nous dériverons la classe abstraite Visitor pour créer des Visiteurs actifs. Notre exemple repose sur deux visiteurs différents : SurfaceVisitor et PerimeterVisitor. Leur code source se trouve dans le fichier zip d'annexe et ne contient que des calculs mathématiques simplistes.

La dernière étape de notre projet consiste à lancer le processus de visite à proprement parler. Le listing suivant présente le code source exécutant la visite des surfaces :

Visitor v = new SurfaceVisitor();
Shape[] s = buildShapes();
for (int i = 0; i < s.Length; i++)
{
  v.visit(s[i] as Circle);
  v.visit(s[i] as Rectangle);
}
Console.WriteLine("La surface totale est de : " + (v as SurfaceVisitor).Surface);
       
      
JextCopier dans Jext
L'emploi abusif de l'opérateur "as" simplifie nettement le code. Les deux appels à la méthode visit() se justifient par la volonté d'instancier nos visiteurs en tant que type parent Visitor. Lorsque la conversion explicite par l'entremise de "as" n'est pas possible, la valeur null se voit donnée en paramètre à visit(). C'est pourquoi nos méthodes visit() prennent soin de tester la valeur null du paramètre. L'ajout de formes géométriques supplémentaires (des triangles par exemple) nécessitera l'ajout de méthodes abstraites dans Visitor et leurs implémentations dans les classes dérivées.


 Annexes




Le langage C# déjà disponible sous Linux avec le projet Mono.



par Romain Guy
romain.guy@jext.org
http://www.jext.org
Dernière mise à jour : 14/10/2006



 
#ProgX©2005 Mathieu GINOD - Romain GUY - Erik LOUISE