schémas récurrents pour construire des programmes orientés objets propres et bien conçus
questions sous-jacentes
comment les objets sont en relations les uns avec les autres ?
comment doivent-ils être couplés ?
que devraient-ils connaître les uns des autres ?
comment peut-on "swap out" les parties qui changent fréquemment ?
principes sous-jacents
séparer les choses constantes des choses qui changent
causes de changements : nouvelle plateforme, apparition bug, changement cahier des charges...
programmer vers une interface, pas une implémentation
permet de mieux résister aux changements
programmer vers le type le plus général possible
pas nécessairement en implémentant une classe d'interface
préférer la composition à l'héritage
pb héritage : classe mère et filles sont très liées, un chgt dans la mère a des impacts partout...
composition : une classe n'hérite plus, mais est composée de différents d'objets fournissant chacun une fonctionnalité
schéma
déléguer, déléguer, déléguer
Template Method Pattern
permet de varier un algorithme
classe abstraite avec méthode squelette (dite aussi "template method")
méthode squelette appelle des méthodes abstraites
c'est la chose qui ne change pas (le squelette de l'algo)
ces méthodes abstraites sont implémentées par les sous-classes concrètes
ce sont les choses qui changent
la méthode squelette n'est pas redéclarée dans les sous classes
hook method : méthode non abstraite dans la classe abstraite
une sous classe peut choisir de la réimplémenter ou pas, dans ce cas elle utilise l'implémentation par défaut de la classe mère
the Template Method pattern is at its best when it is at its leanest—that is, when every abstract method and hook is there for a reason.
ce pattern est réutilisé dans d'autres patterns
Strategy Pattern
on définit l'algorithme dans son entier dans un objet ou classe dédiée
on définit ainsi une famille de objets, les stratégies, qui font toutes le même genre de chose
les stratégies partagent une interface commune, définie ou non dans une classe mère abstraite
le contexte désigne l'utilisateur l'objet/classe utilisateur des stratégies
avantages
le contexte peut choisir sa stratégie à l'initialisation, et la changer au cours du runtime
séparation des responsabilités : le contexte n'a plus de connaissance ni de responsabilités de l'implémentation des stratégies
différence avec le Template Method Pattern
With the Template Method pattern, we make our decision when we pick our concrete subclass.
In the Strategy pattern, we make our decision by selecting a strategy class at runtime.
choix pour passer les données du contexte vers la stratégie
en les énumérant au moment de l'appel de la stratégie
bonne séparation du contexte et de la stratégie
lourd si beaucoup de données à passer
en passant entièrement le contexte dans l'appel de la stratégie
simplifie le flux de données à transmettre
mais augmente le couplage entre stratégies et contexte
en Ruby on peut implémenter les stratégies directement sous forme de proc ou code blocs
on peut ainsi passer à sort une stratégie de tri sous forme d'un code bloc
risque de ce pattern : trop coupler le contexte et les stratégies & faire une mauvaise interface entre les deux
Observer Pattern
permet d'alerter d'autres objets (les observers) quand un objet change (le subject), en réduisant le couplage et en le rendant générique
en Ruby il suffit de mixer le module Observable (require 'observer')
ensuite dans le update du sujet, on utilise "change; notify_observer(self)"
après l'instaciation d'un sujet, il faut explicitement lier le sujet et les observers
deux choix pour l'implémentation de l'interface entre sujet et observers
pull method
une seule méthode dans l'observer avec pour seul argument le sujet en entier
push method
un ou plusieurs méthodes dans l'observer avec des signatures plus complexes et restreintes que le sujet en entier
quand une erreur a lieu dans un observer, faut-il rollbacker le changement au niveau du sujet ?
décision au cas par cas
Composite Pattern
utile pour du code travaillant sur un arbre d'objets sans que le code ait besoin de savoir s'il traite à un moment donné une feuille de l'arbre ou un sous-arbre
3 parties pour construire le composite pattern
component : interface commune pour tous les objets
leaf classes : le bloc de base indivisible
doit implémenter l'interface du component
composite : construits à partir de plusieurs blocs
doit implémenter l'interface du component
Iterator Pattern
fournit à un objet agrégrant une façon d'accéder à ses éléments séquentiellement sans exposer sa représentation interne
deux types d'itérateurs
itérateur externe : l'itérator est un objet distinct de l'objet aggrégeant
on contrôle le rythme de l'itération, on peut la susprendre ou l'interrompre (moins souple avec itérateur interne)
on peut les partager
itérateur interne : l'itération est effectuée par l'objet agrégeant lui-même
on passe à l'objet aggrégeant le code à appliquer à chacun de ses éléments
exemple : each
simples et code plus clair
en Ruby on peut facilement ajouter un itérateur interne à un objet aggrégeant en mixant Enumerable
Command Patern
Command pattern command is an instruction to do something, something specific
a Command pattern command can be filled—or executed—right now, or later, or when something specific happens.
command : object that does nothing but wait to be executed and, when executed, goes out and performs an application-specific task.
en ruby facilement implémentable sous forme de code block / Proc
on sépare ce qui change (la commande) de ce qui ne change pas (dans ex GUI, la classe générique Bouton)
command pattern: ensemble de classes qui partagent une même interface
exemple d'interface
initialize: pour stocker les infos nécessiares à l'exécution de la commande
execute: réalise la commande
describe : décrit la commande
unexecute : annule le résultat de la commande
conseils
n'utiliser que si vraiement où a besoin de faire plus tard une commande et de savoir comment la faire
s'assurer que les circonstances au moment où la commande est exécutée satisfont ses pré requis
par exemple pour une commande annulant une exécution
exemple : les migrations Rails
proche du pattern observer
command et observer sont appelés à partir d'un autre participant du pattern
command n'est pas à priori intéressé par l'objet l'appelant
l'observer si
“one object stands in for another” patterns
Proxy Pattern
un objet (le proxy) prend la place d'un autre
il délègue au vrai objet (@subject) une partie des tâches et en réalise d'autres
par exemple un proxy peut impplémenter du contrôle d'accès sur une classe initiale qui en est dépourvue
cela permet de séparer deux problèmatiques dans 2 classes
l'initiale pour le domaine métier
le proxy pour le contrôle d'accès
intérêts
meilleure séparation des responsabilités
changements plus faciles
en Ruby un proxy est très facilement implémentable avec method_missing et send
Decorator Pattern
straightforward technique that you can use to assemble exactly the functionality that you need at runtime
It offers an alternative to creating a monolithic “kitchen sink” object that supports every possible feature or a whole forest of classes and subclasses to cover every possible combination of features
enables you to easily add an enhancement to an existing object
also allows you to layer features atop one another so that you can construct objects that have exactly the right set of capabilities that you need for any given situation
The ConcreteComponent is the “real” object, the object that implements the basic component functionality
Decorator class
has a reference to a Component—the next Component in the decorator chain
it implements all of the methods of the Component type
layers its own special magic onto the workings of the base component, adding its own talent to at least one of the methods
can also add new methods—that is, operations that are not defined in the Component interface—although this behavior is optional
en Ruby
on peut rapidement implémenter l'interface du Component dans la classe Decorator avec le module Forwardable
on peut changer les classes Decorator en module et les ajouter dynamiquement a un concretecomponent avec extend
mais difficule ensuite de retirer le décorateur
limites
One thing to keep in mind when implementing the Decorator pattern is that you need to keep the component interface simple. You want to avoid making the component interface overly complex, because a complex interface will make it that much harder to get each decorator right.
facilite le travail du codeur implémenteur, mais peut être difficile à utiliser pour le codeur utilisateur
performance overhead si longues chaînes de décorateurs
peut-être plus difficile à débugger
Adaptater Pattern
objet qui fait le lien entre une interface que l'on a et une interface dont on a besoin
dans le graph, on (le client) veut communiquer avec Adaptee, mais son interface ne convient pas
donc en fait on communique avec Target, qui est en fait un adaptateur offrant une meilleure interface que Adaptee
en Ruby on peut facilement modifier l'inteface d'un objet (ou d'une classe) existant plutôt que de créer un adaptateur