You are on page 1of 44

Design patterns - p.

1
Design patterns
Design patterns - p. 2
Définition
• Les design patterns ou modèles de
conception décrivent des organisations
pratiques de classes d’objets.
• Forme d'organisation transposable à
plusieurs applications.
• Éviter d’être saturé par la complexité du
codage (effet spaghetti).
Design patterns - p. 3
Catégories
• Trois grandes catégories
– Les modèles de création : Ces modèles sont très
courants pour désigner une classe chargée de
construire des objets.
– Les modèles de structure : Ces modèles tendent à
concevoir des agglomérations de classes avec des
macro-composants.
– Les modèles de comportement : Ces modèles tentent
de répartir les responsabilités entre chaque classe.
Design patterns - p. 4
Modèles de création
• Fabrique de création
– Une fabrique de création (ou factory) est une
classe qui n'a pour rôle que de construire des
objets.
– Cette classe utilise des interfaces ou des
classes abstraites pour masquer l'origine des
objets.
Design patterns - p. 5
Fabrique de création
• Utile lorsque :
– Les créations entraînent des duplications du
code au détriment de la réutilisation
– L’objet composé n’a pas besoin de connaître
les informations ou ressources utiles à la
création
– La gestion de la durée de vie des objets doit
être centralisée
Design patterns - p. 6
Fabrique de création
/** Interface de description d'un point */
public interface Point {
/** Retourne l'abscisse du point */
public int getX();
/** Retourne l'ordonnée du point */
public int getY();
}
public interface Line { ... }
/** Fabrique retournant des objets de types point ou ligne */
public class CanvasFactory {
/** Retourne un Point aux coordonnées x,y */
public Point getPoint( int x, int y ) {
return new PointImpl( x, y );
}
/** Retourne une Ligne aux coordonnées x1,y1,x2,y2 */
public Line getLine( int x1, int y1, int x2, int y2 ) {
return new LineImpl( x1, y1, x2, y2 );
}
}
• Exemple
Cette classe
masque la
véritable
Nature
des objets.
Design patterns - p. 7
Fabrique abstraite
• Elle retourne un pointeur abstrait sur un
objet concret
• Le client n’a pas à connaître le type concret
• Seulement à l’utiliser via l’interface
abstraite
• La fabrique permet de localiser l’endroit du
code où les objets sont construits
• Singleton
Design patterns - p. 8
Fabrique abstraite
• Exemple
masque la
véritable
Nature
des objets.
Design patterns - p. 9
Modèles de création
• Modèle Singleton
– Ce modèle s’utilise lorsque il n’y a qu’une unique
instance d’une classe et qu’elle doit être accessible
de manière connue.
Design patterns - p. 10
Modèles Singleton
• Modèle Singleton
• Le modèle garantit l’unicité de l’objet créé
et l’interdiction d’instanciations multiples
class Singleton {
private static Singleton unique = new Singleton();
private Singleton() {}
Public static Singleton getInstance() {
return unique;
}
}
Design patterns - p. 11
Modèles de création
• Builder
– Le Builder ou Monteur est une classe offrant
des moyens de construction d'un objet.
– Définit comment s’effectue la création.
– Exécuter les étapes de la création.
Design patterns - p. 12
Builder
Design patterns - p. 13
Builder
/** "Product" */
class Pizza {
private String dough = "";
private String sauce = "";
private String topping = "";
public void setDough(String dough) {
this.dough = dough;
}
public void setSauce(String sauce) {
this.sauce = sauce;
}
public void setTopping(String topping) {
this.topping = topping;
}
}
Design patterns - p. 14
Builder
/** "Abstract Builder" */
abstract class PizzaBuilder {
protected Pizza pizza;
public Pizza getPizza() {
return pizza;
}
public void createNewPizzaProduct()
{
pizza = new Pizza();
}
public abstract void buildDough();
public abstract void buildSauce();
public abstract void buildTopping();
}
Design patterns - p. 15
Builder
/** "ConcreteBuilder" */
class HawaiianPizzaBuilder extends PizzaBuilder {
public void buildDough() {
pizza.setDough("cross");
}
public void buildSauce() {
pizza.setSauce("mild");
}
public void buildTopping() {
pizza.setTopping("ham+pineapple");
}
}
/** "ConcreteBuilder" */
class SpicyPizzaBuilder extends PizzaBuilder {
public void buildDough() {
pizza.setDough("pan baked");
}
public void buildSauce() {
pizza.setSauce("hot");
}
public void buildTopping() {
pizza.setTopping("pepperoni+salami");
}
}
Design patterns - p. 16
Builder
/** "Director" */
class Cook {
private PizzaBuilder pizzaBuilder;
public void setPizzaBuilder(PizzaBuilder pb) {
pizzaBuilder = pb;
}
public Pizza getPizza() {
return pizzaBuilder.getPizza();
}
public void constructPizza() {
pizzaBuilder.createNewPizzaProduct();
pizzaBuilder.buildDough();
pizzaBuilder.buildSauce();
pizzaBuilder.buildTopping();
}
}
Design patterns - p. 17
Builder
/** A given type of pizza being constructed. */
public class BuilderExample {
public static void main(String[] args) {
Cook cook = new Cook();
PizzaBuilder hawaiianPizzaBuilder = new HawaiianPizzaBuilder();
PizzaBuilder spicyPizzaBuilder = new SpicyPizzaBuilder();
cook.setPizzaBuilder(hawaiianPizzaBuilder);
cook.constructPizza();
Pizza pizza = cook.getPizza();
}
}
Design patterns - p. 18
Modèles de structure
• Ces modèles de conception tentent de
composer des classes pour bâtir de
nouvelles structures.
• Les objets ainsi conçus forment un nouvel
objet que l'on peut déplacer, et manipuler
sans avoir à répéter ces opérations sur
chaque objet qui le compose.
Design patterns - p. 19
Adapter
• Adapter (wrapper pattern)
– Faire fonctionner un objet avec une interface
qu'il ne possède pas.
– Classe supplémentaire qui se charge
d'implémenter la bonne interface (L'Adapteur)
et d'appeler les méthodes correspondantes
dans l'objet à utiliser (L'adapté).
Design patterns - p. 20
Adapter
Design patterns - p. 21
Adapter
• Exemple
/** Interface de représentation d'un cercle */
public interface Circle {
public int getX();
public int getY();
public int getR();
}
/** Classe implémentant l'interface Circle */
public class CircleImpl implements Circle {
...
}
/** Adapteur pour transformer le circle en un point */
public class CircleImplPointAdapter implements Point {
private Circle c;
public CircleImplPointAdapter( Circle c ) {
this.c = c;
}
public int getX() { return c.getX(); }
public int getY() { return c.getY(); }
}
Design patterns - p. 22
Bridge
• Bridge
– Éviter un lien permanent entre l'abstraction et
l'implantation (ex: l'implantation est choisie à
l'exécution).
– Abstraction et implantation sont toutes les
deux susceptibles d'être raffinées.
– Les modifications subies par l'implantation ou
l'abstraction ne doivent pas avoir d'impacts sur
le client (pas de recompilation).
Design patterns - p. 23
Bridge
Design patterns - p. 24
Bridge
/** "Implementor" */
interface DrawingAPI {
public void drawCircle(double x, double y, double radius);
}
/** "ConcreteImplementor" 1/2 */
class DrawingAPI1 implements DrawingAPI {
public void drawCircle(double x, double y, double radius) {
System.out.printf(
"API1.circle at %f:%f radius %f\n",
x, y, radius);
}
}
/** "ConcreteImplementor" 2/2 */
class DrawingAPI2 implements DrawingAPI {
public void drawCircle(double x, double y, double radius) {
System.out.printf(
"API2.circle at %f:%f radius %f\n",
x, y, radius);
}
}
• Exemple
Design patterns - p. 25
Bridge
/** "Abstraction" */
interface Shape {
public void draw();// low-level
public void resizeByPercentage(double pct);// high-level
}
/** "Refined Abstraction" */
class CircleShape implements Shape {
private double x, y, radius;
private DrawingAPI drawingAPI;
public CircleShape(
double x, double y, double radius,
DrawingAPI drawingAPI) {
this.x = x;
this.y = y;
this.radius = radius;
this.drawingAPI = drawingAPI;
}
/** low-level i.e. Implementation specific */
public void draw() { drawingAPI.drawCircle(x, y, radius); }
/** high-level i.e. Abstraction specific */
public void resizeByPercentage(double pct) { radius *= pct; }
}
• Exemple
Design patterns - p. 26
Bridge
• Exemple
/** "Client" */
class BridgePattern {
public static void main(String[] args) {
Shape[] shapes = new Shape[2];
shapes[0] = new CircleShape(1, 2, 3, new DrawingAPI1());
shapes[1] = new CircleShape(5, 7, 11, new DrawingAPI2());
for (Shape shape : shapes) {
shape.resizeByPercentage(2.5);
shape.draw();
}
}
}
Design patterns - p. 27
Proxy
• Proxy et decorator
– Ajouter un niveau de redirection entre l'appel
d'une méthode d'un objet et l'action associée.
– Une nouvelle classe implémente l'interface de
l'objet à manipuler et déporte toutes les actions
sur un autre objet implémentant la même
interface.
– Changer l'objet cible sans changer l'objet
source (manipulé).
Design patterns - p. 28
Proxy
Design patterns - p. 29
Proxy
• Exemple
/** Interface représentant un espace de dessin */
public interface Canvas {
/** Ajout d'un objet graphique */
public void addGraphicElement( GraphicElement ge );
}
/** Proxy pour l'espace de dessin */
public class CanvasProxy implements Canvas {
private Canvas c;
public CanvasProxy( Canvas c ) {
this.c = c;
}
public void addGraphicElement( GraphicElement ge ) {
c.addGraphicElement( ge );
}
}
Design patterns - p. 30
Decorator
• Exemple : la classe BufferedReader() de
l’API Java
• BufferedReader in = new
BufferedReader(new FileReader("file.txt"));
Design patterns - p. 31
Composite
• Composite
– Composition récursive d’objets.
– Représenter une hiérarchie d'objets.
– Ignorer la différence entre un composant
simple et un composant en contenant d'autres
(interface uniforme).
– Exemple du groupe d'objets dans un logiciel
de dessin.
Design patterns - p. 32
Composite
Design patterns - p. 33
Composite
/** Composant */
public interface Graphic {
public void print();
}
/** Composite */
public class CompositeGraphic implements Graphic {
private List<Graphic> mChildGraphics = new ArrayList<Graphic>();
public void print() {
for (Graphic graphic : mChildGraphics) {
graphic.print();
}
}
/** Ajout d'un objet graphique */
public void add( Graphic ge );
}
/** Feuille */
public class Ellipse implements Graphic {
public void print() { System.out.println("Ellipse"); }
}
Design patterns - p. 34
Modèles de comportement
• Ils décrivent la manière dont les objets
interagissent entre eux.
• Iterator
• Observer
• Visitor
Design patterns - p. 35
Iterator
• Accéder aux éléments d’un objet sans en
exposer la structure.
• Offrir une interface uniforme pour parcourir
différents types d’objets.
• Implémenté dans l’API java via l’interface
java.util.Iterator
Design patterns - p. 36
Iterator
Design patterns - p. 37
Observer
• Lorsqu’on souhaite que le changement
d’un objet affecte d’autres objets.
• Que cet objet ne connaisse pas a priori les
objets à notifier.
• Implémenté dans l’API java via la classe
java.util.Observable et l’interface
java.util.Observer.
Design patterns - p. 38
Observer
Design patterns - p. 39
Visitor
• Permet de parcourir une structure.
• Pour y appliquer des opérations définies
indépendamment de la structure.
• Applique des opérations qui dépendent à la
fois des éléments de la structure et du type
d’implantation des opérations.
• Technique du « double dispatch ».
Design patterns - p. 40
Visitor

[0,N]
CVisiteur
VisiteElementConcretA(unElementConcretA)=0
VisiteElementConcretB(unElementConcretB)=0
CVisiteurConcret1
VisiteElementConcretA(unElementConcretA)
VisiteElementConcretB(unElementConcretB)
CVisiteurConcret2
VisiteElementConcretA(unElementConcretA)
VisiteElementConcretB(unElementConcretB)
CElement
Accept(CVisiteur v)
CElementConcretA
Accept(CVisiteur v) {
v-> VisiteElementConcretA(this) ; }
CElementConcretB
Accept(CVisiteur v) {
v-> VisiteElementConcretB(this) ; }
CElementCollection
Visite(CVisiteur v){
Pour chaque élément appelle Accept(v);}


Client
Design patterns - p. 41
Visitor

unCElementCollection unCElementConcretA unCElementConcretB unCVisiteurConcret
Temps
Effectue l’opération
VisiteElementConcretA(unElementConcretA)
Accept(unVisiteurConcret)
Effectue l’opération
VisiteElementConcretB(unElementConcretB)
Accept(unVisiteurConcret)
Design patterns - p. 42
Visitor
• L’ajout d’une opération sur les éléments est
très facile puisqu’il suffit d’ajouter une
classe dérivée de CVisiteur.
• Les opérations similaires sur des
CElement différents sont réunies, et les
opérations différentes sont séparées, par
architecture.
• Les classe CElementConcret ne sont
pas surchargées par des opérations.
Design patterns - p. 43
Visitor
• Technique du « Double dispatch » :
– Le polymorphisme s’applique sur deux types.
– D’abord le polymorphisme s’applique dans la méthode
CElementCollection::Accept() sur les
classes dérivées de CElement.
– Ensuite le polymorphisme s’applique dans la méthode
CElementConcret::VisiteElementConcret
() sur les classes dérivées de CVisiteur.
Design patterns - p. 44
Visitor