Patron de méthode
La technique du patron de méthode (template method pattern) est une technique reposant sur un patron de conception (design pattern) comportemental utilisé en génie logiciel.
Un patron de méthode définit le squelette d'un algorithme à l'aide d'opérations abstraites dont le comportement concret se trouvera dans les sous-classes, qui implémenteront ces opérations.
Cette technique, répandue dans les classes abstraites, permet de:
- fixer clairement des comportements standards qui devraient être partagés par toutes les sous-classes, même lorsque le détail des sous-opérations diffère ;
- factoriser le mode du code qui serait redondant s'il se trouvait répété dans chaque sous-classe.
La technique du patron de méthode se déploie par la méthode de la classe parent qui appelle les opérations n'existant que dans les sous-classes. C'est une pratique courante dans les classes abstraites, alors que d'habitude dans une hiérarchie de classes concrètes, l'opposé prévaut. Cette opposition annonce les méthodes des sous-classes qui rappellent celles de la super-classe comme partie prise de leur propre comportement.
L'implémentation d'un patron de méthode est aussi appelée méthode socle parce qu'elle ancre solidement un comportement qui s'applique alors à toute la hiérarchie des classes par héritage. Pour s'assurer que ce comportement ne sera pas redéfini arbitrairement dans les sous-classes, on inscrit la méthode socle final en Java, non virtuelle en C++ ou approuvée en C#.
Les méthodes servant de «briques de comportement» à la méthode socle devraient être déclarées abstract en Java, virtuelles pures en C++ et abstract en C#.
Exemple en Java
/**
* Classe abstraite servant de base commune à divers
* jeux de société où les joueurs jouent chacun leur tour.
*/
abstract class JeuDeSociété{
protected int nombreDeJoueurs;
abstract void initialiserLeJeu();
abstract void faireJouer(int joueur);
abstract boolean partieTerminée();
abstract void proclamerLeVainqueur();
/* Une méthode socle : */
final void jouerUnePartie(int nombreDeJoueurs){
this.nombreDeJoueurs = nombreDeJoueurs;
initialiserLeJeu();
int j = 0;
while( ! partieTerminée() ){
faireJouer( j );
j = (j + 1) % nombreDeJoueurs;
}
proclamerLeVainqueur();
}
}
Cette classe est dérivée pour implanter divers jeux:
Cette classe est dérivée pour implanter divers jeux:
class Monopoly extends JeuDeSociété{
/* Implémentation concrète des méthodes nécessaires */
void initialiserLeJeu(){
// ...
}
void faireJouer(int joueur){
// ...
}
boolean partieTerminée(){
// ...
}
void proclamerLeVainqueur(){
// ...
}
/* Déclaration des composants spécifiques au jeu du Monopoly */
// ...
}
class Echecs extends JeuDeSociété{
/* Implémentation concrète des méthodes nécessaires */
void initialiserLeJeu(){
// ...
}
void faireJouer(int joueur){
// ...
}
boolean partieTerminée(){
// ...
}
void proclamerLeVainqueur(){
// ...
}
/* Déclaration des composants spécifiques au jeu d'échecs */
// ...
}
La technique du patron de méthode fixe un cadre pour toutes les sous-classes. Cela implique certaines restrictions : dans l'exemple ci-dessus, on ne peut pas faire hériter une classe Jeu Du Tarot de la classe abstraite Jeu De Société, parce que dans une partie de tarot, l'ordre des joueurs n'est pas linéaire. En fait, il dépend du joueur qui vient de ramasser le pli des cartes.
On peut décider de ne pas déclarer la méthode socle comme final en Java (ou bien décider de la déclarer virtuelle en C++), afin de la rendre plus souple. Ainsi la classe Jeu Du Tarot pourrait parfaitement hériter de la classe Jeu De Société, à condition de redéfinir la méthode jouer une partie pour tenir compte des règles du tarot. Mais cette pratique pourrait conduire à une critique. Il est important de se poser la question dès l'écriture de la super-classe : les sous-classes auront-elles le droit de redéfinir les comportements fondamentaux codés dans la super-classe ? L'avantage est bien sûr une souplesse accrue. L'inconvénient peut être la perte de la cohérence interne de l'objet, si la surcharge des méthodes socles est mal conçue.
Pour reprendre l'exemple précédent, on pourrait mettre en place une méthode retournant le prochain joueur, qui serait implémentée différemment dans la classe Jeu Du Tarot et dans la classe d'un jeu où chaque joueur joue successivement comme dans un jeu de carte appelé Bridge.