Aujourd’hui je vais tenter de vous expliquer comment fonctionne l’un des Design Patterns les plus utilisé qui fut initialement proposé par le GOF (Gang Of Four) : le Design Pattern Stratégie.
Pour commencer, il peut être intéressant de rappeler ce que sont les Design Pattern ou “Motifs de conception” en français. Les Design Patterns sont un ensemble de solutions standards permettant de répondre à des problèmes de conception rencontrés lors du développement de projets orientés objet. Les Design Patterns se regroupent dans trois grands groupes : Créationnel, Structurel et Comportemental. Le motif de conception que l’on va voir aujourd’hui fait partie du dernier groupe : les comportementaux.
Le Design Pattern Stratégie
Description :
L’intérêt principal de ce motif de conception est de permettre l’encapsulation d’algorithmes et de les rendre permutables. En effet, imaginons que l’on souhaite changer dynamiquement le comportement d’un objet et cela sans modifier la classe de ce dernier. A première vue, celà semble plutôt compliqué… mais il n’en est rien ![]()
Prenons un exemple simple : Une classe Personne qui a le dont de se déplacer. On peut imaginer plusieurs types de déplacements : marcher, courir !
De manière générale on aurait tendance à créer une méthode par déplacement :
Exemple en Python:
def marcher(self):
print “je marche”
def courir(self):
print “je cours”
Exemple en PHP 5 :
C’est pas mal, mais rien de très dynamique ! En effet, imaginons que l’on souhaite ajouter un nouveau comportement de déplacement (par exemple : nager) il faudra ajouter une nouvelle méthode.
Stratégie va permettre à notre classe Personne de posséder un comportement de déplacement dynamiquement interchangeable. Pour cela nous devons externaliser les comportements de la classe en utilisant un système bien connu en POO : la composition.
Regardons le diagramme de classe suivant :
Le diagramme UML :
Ce schéma mérite une petite explication. Comme on peut le voir, la classe Personne ne possède plus les trois méthodes “marcher“, “courir” mais elles ont été remplacées par deux autres : “setMouvement” et “déplacer“. La première va nous permettre d’attribuer aux instances de la classe Personne un objet Mouvement. La seconde quant à elle va exécuter le mouvement précédemment attribué à l’objet Personne. Les comportements sont désormais des classes à part entière qui implémente l’interface Mouvement.
Exemple en python :
def __init__(self):
self.__mouvement = None
def setMouvement(self, mouvement):
self.__mouvement = mouvement
def deplacer(self):
if self.__mouvement:
self.__mouvement.execute()
class Mouvement:
def execute(self):
raise “Doit être implementé”
class Marcher(Mouvement):
def execute(self):
print “je marche”
class Courir(Mouvement):
def execute(self):
print “je cours”
pers = Personne()
unMouvement = Marcher()
pers.setMouvement( unMouvement )
pers.deplacer() #affiche "je marche"
unMouvement = Courir()
pers.setMouvement( unMouvement )
pers.deplacer() #affiche "je cours"
En Python la notion d’interface comme en Java ou PHP 5 n’existe pas. J’ai donc fait en sorte, dans mon exemple, que la méthode execute de la classe Mouvement soit obligatoirement redéfinie dans les classes qui étendent de celle-ci.
Exemple en PHP 5 :
{
public function execute();
}
class Marcher implements Mouvement
{
public function execute()
{
print “je marche”;
}
}
class Courir implements Mouvement
{
public function execute()
{
print “je cours”;
}
}
class Personne
{
private $mouvement;
public function setMouvement( Mouvement $mouvement )
{
$this->mouvement = $mouvement;
}
public function deplacer()
{
if( !is_null($this->mouvement) )
{
$this->mouvement->execute();
}
}
}
$pers = new Personne();
$unMouvement = new Marcher();
$pers->setMouvement( $unMouvement );
$pers->deplacer();// affiche "je marche"
$unMouvement = new Courir();
$pers->setMouvement( $unMouvement );
$pers->deplacer();// affiche "je cours"
La méthode deplacer appelle la méthode execute du mouvement passé en paramètre. On s’aperçoit dans cet exemple que comportement de la méthode deplacer est modifiable dynamiquement. Lors de son premier appel elle affiche “je marche” puis “je cours” lors du second appel. Ceci est du au fait que le mouvement passé en paramètre n’est plus le même. Imaginons désormais que l’on doivent ajouter un nouveau comportement de déplacement (par exemple : “nager”), il suffira tout simplement de créer une nouvelle classe nommée Nager qui implémente la classe Mouvement.
def execute(self):
print “je nage”
pers = Personne()
unMouvement = Nager()
pers.setMouvement( unMouvement )
pers.deplacer() #affiche "je nage"
Très pratique si votre boss ne vous à fourni que la version compilée de la classe Personne
On peut modifier son comportement sans toucher une seule ligne de celle-ci.
Et voilà que ce premier tutoriel sur les Design Patterns touche à sa fin. En espérant que ça vous a plu… ![]()

décembre 16th, 2007 at 21:57
Bien sympa
Ca a le merite d’être clair et de rester simple d’approche. J’attend la suite avec impatience ^^
décembre 16th, 2007 at 21:58
Très bon post!
Par contre, je trouve la version Python pas très élégante… N’y a-t-il pas moyen de ruser autrement?
Bonne continuation
décembre 16th, 2007 at 21:58
Intéressant, je le connaissais pas celui là
décembre 16th, 2007 at 21:59
Je suis assez mitigé sur cet article.
Autant je trouve que dans l’exemple, la technique employé est adapté au besoin du code.
Autant je ne trouve pas que cet exemple donne une réelle idée du Design Pattern.
On pourrait le confondre avec la bonne pratique “une et une seule fois” qui tend à ne pas écrire la même tranche de code à deux endroit. Et qui milite contre le “copier/coller”, mais ceci est une autre histoire…
Ainsi, j’aurai souhaité, à la fin de cet article, avoir plus d’exemples sous forme de shémas UML afin de délimiter correctement l’ensemble du groupe comportemental.
Cela dit, le thon est bon je reviendrais.
Le troll qui sommeil en moi répond à :
“Par contre, je trouve la version Python pas très élégante… N’y a-t-il pas moyen de ruser autrement?”
par : en ruby c’est plus joli
def setMouvement mouvement
@mouvement = mouvement
end
def deplacer
if @mouvement != nil
@mouvement.execute()
end
end
end
class Mouvement
def execute
raise “Doit être implementé”
end
end
class Marcher < Mouvement
def execute
puts “je marche”
end
end
class Courir < Mouvement
def execute
puts “je cour” # y’a une faute dis donc :p
end
end
pers = Personne.new
unMouvement = Marcher.new
pers.setMouvement unMouvement
pers.deplacer #affiche “je marche”
unMouvement = Courir.new
pers.setMouvement unMouvement
pers.deplacer #affiche “je cour”
PS : comment on balise le
dans ce machin ?décembre 16th, 2007 at 22:01
@ mickro : Je ne pense pas que ce pattern réponde correctement à la bonne pratique “une et une seule fois”, puisque son but est essentiellement d’encapsuler des algorithmes. En d’autre terme de séparer les choses qui varient de celles que ne le font pas. Dans notre exemple ce qui varie est le comportement de déplacement.
décembre 16th, 2007 at 22:03
… suite a discution en vrai, c’est moi qui est mal cerné l’article.
Je l’avais prit pour une définition du groupe comportemental et forcement je le trouvais incomplet.
Mais comme il s’agit du Design Pattern Stratégie seulement… alors ca est moins pertinent mon comment du coup :p
décembre 16th, 2007 at 22:03
mickro, la version ruby est exactement la même que la Python, ce qui me chifonne un peu c’est la partie:
def execute(self):
raise “Doit être implementé”
Pour simuler une interface. Mais en même temps je vois pas comment faire autrement…
décembre 16th, 2007 at 22:05
Salut !
Je passais pas là par hasard, je suis agréablement surpris par la simplicité de l’explication, appuyé par un exemple que je trouve des plus parlants.
Il manque en effet des artiles de cette pertinence sur la toile, dans le sens où en quelques lignes et sans salamalek, le mot barbare de Design Pattern Strategie a été démystifié.
Pour etre honete avec la terre entiere, j’avoue (mais je rougis :p) que j’utilisais cette methode sans meme m’en rendre compte…
Comme quoi, les Design Patterns, sont en quelques sortes une jurisprudence du code.
décembre 16th, 2007 at 22:05
Hé, super,
je n’utilise jamais les DP (gloups) et là j’ai enfin un article qui e donne envie d’aller plus loin.
Merci, mais j’en veux encore, encore ….
février 11th, 2008 at 23:37
Un grand merci à toi, je suis du même avis que benji on attend la suite (héhéhé)…