• Aucun résultat trouvé

Patrons de conception

N/A
N/A
Protected

Academic year: 2022

Partager "Patrons de conception"

Copied!
37
0
0

Texte intégral

(1)

Patrons de conception

S

- Il s’agit d’un principe du génie logiciel destiné à résoudre, suivant le paradigme objet, des problèmes récurrents.

* Synthèse de situations réelles (ce ne sont pas des créations de toute pièce)

* Orientés problèmes

* Indépendants des situations

« Chaque moule (pattern) décrit un problème qui réapparaît de manière régulière dans notre environnement, puis il décrit le noyau de la solution du problème, de telle manière que vous pouvez réutiliser cette solution autant de fois que vous le voulez, sans jamais réaliser la solution finale deux fois de suite de la même manière »

Christopher Alexander, Architecte (à l'origine de la notion de pattern)

(2)

2

Patrons de conception Objectifs :

- Modularité

* Facilité de gestion (technologie objet) - Cohésion

* Degré avec lequel les tâches réalisées par un seul module sont fonctionnellement reliées

* Une forte cohésion est une bonne qualité - Couplage

* Degré d’interaction entre les modules dans le système

* Un couplage '‘faible’’ est une bonne qualité - Réutilisabilité

* Bibliothèques, frameworks (ensemble cohérent de composants logiciels)

(3)

Cohésion : « mauvais » exemple public class GameBoard {

public GamePiece[ ][ ] getState() { . .. }

// Méthode copiant la grille dans un tableau temporaire, //résultat de l’appel de la méthode.

public Player isWinner() { ... }

// vérifie l’état du jeu pour savoir s’il existe un gagnant, // dont la référence est retournée.

// Null est retourné si aucun gagnant.

public boolean isTie() { ... }

//retourne true si aucun déplacement ne peut être effectué, //false sinon.

public void display () { ... }

// affichage du contenu du jeu. Espaces blancs affichés pour //chacune des références nulles.

}

GameBoard est responsable des règles du jeu et de l’affichage

(4)

4

Cohésion : «bon» exemple public class GameBoard {

public GamePiece[ ][ ] getState() { ... } public Player isWinner() { ... }

public boolean isTie() { ... } }

public class BoardDisplay {

public void displayBoard (GameBoard gb) { ... }

// affichage du contenu du jeu. Espaces blancs affichés // pour chacune des références nulles.

}

(5)

Couplage : exemple

Couplage fort à cause du paramètre "nStudents"

Couplage faible

(et meilleure fiabilité) au travers de l’utilisation de l’attribut "length"

(6)

6

Patrons de conception

- Il existe trois sortes de patrons :

* Création :

– Description de la manière dont un objet ou un ensemble d’objets peuvent être créés, initialisés, et configurés

– Isolation du code relatif à la création

Exemples : Fabrique abstraite (Abstract Factory), Fabrique (Factory Method), Singleton (Singleton)

* Structure:

– Description de la manière dont doivent être connectés des objets de l’application afin de rendre ces connections indépendantes des

évolutions futures de l’application

– Découplage de l’interface et de l’implémentation de classes et d’objets Exemple : Adaptateur (Adapter), Objet composite (Composite),

Décorateur (Decorator), Façade (Facade)

* Comportement:

– Description de comportements d’interaction entre objets

– Gestion des interactions dynamiques entre des classes et des objets Exemple : Etat (State), Itérateur (Iterator), Observateur (Observer), Stratégie (Strategy), Visiteur (Visitor)

(7)
(8)

8

1) Modèles de création:

- On se trouve souvent confronté en programmation objet au problème d'évolution des classes.

- Une classe hérite d'une autre classe pour en spécialiser certains éléments. On aimerait donc qu'un objet puisse appartenir à telle ou telle classe (dans une même famille par héritage) sans avoir à chercher la classe de gestion de ces objets et la ligne de code qui effectue l'instanciation.

(9)

Singleton (création)

- Le singleton est un patron de conception dont l’objet est de restreindre l’instanciation d’une classe à un seul objet.

- Il est utilisé lorsque l’on a besoin d’exactement un objet pour coordonner des opérations dans un système.

Exemple :

Le moteur d’une application graphique.

(10)

10

Exemple

class Singleton {

private static Singleton instanceU =null;

private Singleton(){

// intialisation }

public static Singleton getInstanceU() { if (instanceU == null)

instanceU = new Singleton ();

return instanceU;

} ...

}

- Naturellement il peut y avoir d’autres attributs, et le constructeur (ainsi que la méthode getInstanceU) peut avoir des paramètres.

- Le processus de l'obtention de l'instance permet de créer l'instance unique si celle-ci n'a pas été encore créée, ou de renvoyer l'instance unique existante dans le cas contraire.

(11)

Fabrique (création)

- La fabrique a pour rôle l’instanciation d’objets dont le type exact n’est pas fixé:

les objets sont créés dynamiquement en fonction de la classe de l’instance de fabrique.

- Déléguer à une classe Factory de construire des objets d’une autre classe (Product)

- Une fabrique de création 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.

Client Factory Product

<<use>> <<realize>>

(12)

12

Exemple

public class FabriqueAnimal {

Animal getAnimal(String typeAnimal) throws ExceptionCreation { if (typeAnimal.equals("chat")) {

return new Chat();

}

else if (typeAnimal.equals("chien")) { return new Chien();

}

throw new ExceptionCreation("Impossible de créer un "

+ typeAnimal);

}

public static void main(String [] args){

...

} }

(13)

Fabrique abstraite (création)

- Déléguer à une classe Factory de construire des objets correspondant à une interface. Seule Factory « sait » quel type d’objet construire.

Client AbstractFactory Interface

<<use>> <<realize>>

Product_a Product_b

(14)

14

Exemple :

/** 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();

}

/** Interface de description d'une ligne */

public interface Line {

/** Retourne les coordonnées du premier point */

public int getX1();

public int getY1();

/** Retourne les coordonnées du deuxième point */

public int getX2();

public int getY2();

}

/** 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 );

} }

(15)

Suite...

- Dans cet exemple, nous définissons deux interfaces Point et Line représentant deux classes Abstraites.

- Ces classes Point et Line désignent des objets retournées par la classe CanvasFactory. Cette classe masque la véritable nature des objets.

- Nous retournons par les méthodes d'accès des objets PointImpl et LineImpl qui implémentent respectivement les interfaces Point et Line. Ainsi, l'application utilisera la classe CanvasFactory pour obtenir des éléments graphiques.

- Lors d'une évolution l'utilisateur pourra changer facilement la nature des objets (avec d'autres classes implémentant les interfaces Point et Line...).

(16)

16

Exercice :

Écrivez une classe abstraite Voiture avec trois sous-classes Fiat, Peugeot, Audi, et une Factory qui crée la bonne voiture selon le budget de l’acheteur, sachant qu’une Fiat coûte moins de 10000 euros,une Peugeot entre 10000 et 19999 et une Audi 20000 ou plus

(17)

2) Modèles de structure :

- Ces modèles de conception tentent de composer des classes pour bâtir de nouvelles structures.

- Ces structures servent avant tout à ne pas gérer différemment des groupes d'objets et des objets uniques.

- Tout le monde en utilisant un logiciel de dessin vectoriel est amené à grouper des objets. 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. On obtient donc une structure plus large mais toujours facilement manipulable.

(18)

18

Adapter (structure)

- L'Adapteur ou Adapter est un moyen commode de faire fonctionner un objet avec une interface qu'il ne possède pas.

- L'idée est de concevoir une 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é).

/** Interface de représentation d'un cercle */

public interface Circle {

/** Retou rne l'abscisse du centre du cercle */

public int getX();

/** Retourne l'ordonnée du centre du cercle */

public int getY();

/** Retourne le rayon du cercle */

public int getR();

}

/** Classe implémentant l'interface Circle */

public class CircleImpl implements Circle { ...

}

/** Adapteur pour transformer le cercle 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(); } }

(19)

Exemple

- Cet exemple tente de convertir un objet implémentant l'interface Circle en un objet de type Point.

- Une classe CircleImplPointAdapter va réaliser cette liaison se chargeant d'implémenter l'interface Point et d'appeler les méthodes du Cercle analogue à celle du Point, en l'occurrence getX et getY.

- L'adapteur sert donc à lier des classes indépendantes n'ayant pas les bonnes interfaces. Cette exploitation est réservée au cas particulier où le changement d'une classe mère serait impossible ou trop complexe.

- Attention cependant à ne pas accroître de manière inconsidérée le nombre de classe par l'introduction d'adapteur à tous les niveaux. L'adapteur reste un moyen pour effectuer des "raccords".

(20)

20

Composite (structure)

- Un objet composite est constitué d’un ou de plusieurs objets similaires.

L’objectif est de manipuler un groupe d’objets comme s’il s’agissait d’un seul objet. Les objets ainsi regroupés doivent posséder des opérations communes, c'est-à-dire un "dénominateur commun".

- Le modèle Composite cherche à éliminer toute différence entre un groupe d'objets et un objet.

- L'exemple le plus simple étant celui du groupe d'objets dans un logiciel de dessin comme nous l'avons vu précédemment. La manière la plus simple pour gérer ces modèles est l'exploitation d'une interface unique pour les éléments simples et l'élément "composé".

-abstraction pour tous les composants, y compris ceux qui sont composés -déclare l'interface pour le comportement par défaut

-représente un composant n'ayant pas de sous-éléments -implémente le comportement par défaut

-représente un composant pouvant avoir des sous-élément -stocke des composants enfants et permet d'y accéder -implémente un comportement en utilisant les enfants

(21)

Exemple

public interface Composant {

protected Composite parent = null; /* Optionnel */

public void operation();

}

class Feuille implements Composant { Composant parent ;

public void operation() { /* Code de la méhode */

}

/* Les autres méthodes sont vides */

}

(22)

22

class Composite implements Composant {

private ArrayList<Composant> enfants =

new ArrayList<Composant>();

public void operation() { /* Méthode clé */

for(Iterator<Composant> it=enfants.iterator();

it.hasNext(); ) (it.next()).operation();

}

public void ajout(Composant comp) { enfants.add(comp);

}

public void retrait(Composant comp) { enfants.remove(comp);

}

public Composant getFils(int i){

return enfants.get(i);

} }

(23)

Décorateur (structure)

- Le décorateur permet d’ajouter dynamiquement des capacités à un objet.

- Dans la programmation orientée objet, la façon la plus classique d’ajouter des fonctionnalités à une classe est d’utiliser l’héritage. Pourtant il arrive parfois de vouloir ajouter des fonctionnalités à une classe sans utiliser l’héritage. En effet, si l’on hérite d’une classe la redéfinition d’une méthode peut entraîner l’ajout de nouveaux bugs. On peut aussi être réticent à l’idée que des méthodes de la classe mère soient appelées directement depuis notre nouvelle classe.

Exemple : voir cours E/S

classe abstraite héritant de Composant et ayant un attribut de type Composant

Pour ajouter des fonctionnalités à un ensemble de ComposantConcret

(24)

24

Exercice :

Motif Composite

Préparation : écrire une classe "Met" qui possède les méthodes : toString() qui renvoie le nom de ce met et les informations suivantes estSucre(), estSale(), estSucreSale(), le nombreDeCalories() et si c'estDietetique() (nombre de kcalories inférieur à 200).

Écrire les classes Sucre, Sel, Poire, Pomme, Framboise, Veau, Boeuf, Chocolat, Carotte, Haricot _vert qui héritent de Met.

On souhaite représenter un plat composé (un boeuf carotte par exemple) également comme un met particulier. Dans ce cas, la méthode toString() renvoie la liste des ingrédients du met composé. Un met est alors sucré si au moins un des éléments est sucré, salé si un au moins est salé et sucré-salé quand il est sucré et salé.

Créez vos propres recettes, en notant que vous pouvez créér un met composé de mets eux-mêmes composés, et de plusieurs fois le même met dans un programme de test.

(25)

Motif Decorator

On désire maintenant créer une nouvelle sorte de Mets dits "allégés" (ils sont tous diététiques). On ne veut pas changer les classes existantes (mais en rajouter de nouvelles), de manière à avoir par exemple du Boeuf allégé, etc...

- Ici notre classe décorateur est une classe qui hérite de la classe à décorer et prend dans son constructeur une instance de la classe décorée.

- Elle effectue des modifications dans son traitement initial (par exemple ici : redéfinition de la méthode estDietetique()) .

- Vous devez également changer les méthodes d'affichage pour "embellir" le produit .

(26)

26

3) Modèles de comportement:

- Les modèles de comportement simplifient l'organisation d'exécution des objets.

- D'une manière générale, un modèle de de comportement permet de réduire la complexité de gestion d'un objet ou d'un ensemble d'objet.

(27)

Itérateur (comportement)

- L'Itérateur ou Iterator est le plus commun des modèles de comportement. L'idée étant de limiter la vision d'une collection par un utilisateur.

- Une collection contient un ensemble d'objets stockés par différentes méthodes (un tableau, un vecteur...), l'exploitant qui accède au contenu de la collection ne souhaite pas être concerné par cette manière de gérer les objets. La collection offre donc un point d'accès unique sous la forme d'une interface Iterator.

Définit une interface pour parcourir et accéder aux éléments

Implémente l'interface Iterateur Définit une interface pour créer un objet itérateur

(28)

28

Exemple

class Pile<E> extends Queue<E>{

public Iterator<E> iterator() {

Iterator<E> iter = new StackIterator<E>();

return iter;

} }

class StackIterator<E> implements Iterator<E>{

int cur;

public Iter(){

cur = Pile.this.nbElem-1;

}

public boolean hasNext() { return cur>=0;

}

public F next() {

return (F)Pile.this.content[cur--];

} }

(29)

Stratégie (comportement)

- Le patron stratégie permet à des algorithmes d’être sélectionnés à la volée au cours du temps d'exécution selon certaines conditions.

- Permet aux algorithmes d’évoluer indépendamment de leurs clients.

(30)

30

Exemple

abstract class Strategie{

...

public int choixAttaque();

}

class RandomStrategie extends Strategie{

public int choixAttaque(){

return ranGene.nextInt(3);

} }

class StrategieMimic extends Strategie{

public int choixAttaque(){

return previous;

} }

class PatternStrategie extends Strategie{

private pattern = {0,1,2};

public int choixAttaque(){

return pattern[(nbA++)%patern.length];

} }

(31)

public interface PaymentStrategy { public void pay(int amount);

}

public class CreditCardStrategy implements PaymentStrategy { private String name;

private String cardNumber;

private String cvv;

private String dateOfExpiry;

public CreditCardStrategy(String nm, String ccNum, String cvv, String expiryDate){

this.name=nm;

this.cardNumber=ccNum;

this.cvv=cvv;

this.dateOfExpiry=expiryDate;

}

@Override

public void pay(int amount) {

System.out.println(amount +" paid with credit/debit card");

} }

public class PaypalStrategy implements PaymentStrategy { private String emailId;

private String password;

public PaypalStrategy(String email, String pwd){

this.emailId=email;

this.password=pwd;

}

@Override

public void pay(int amount) {

System.out.println(amount + " paid using Paypal.");

(32)

32

Observateur (comportement)

- L’observateur permet à un ensemble d’objets (les observateurs) d’être avertis de changements sur un objet particulier (le sujet).

(33)

- L’interface Observateur sera implémenté par toutes classes qui souhaitent avoir le rôle d’observateur. C’est le cas de la classe ObservateurConcret qui implémente la méthode actualiser(Observable). Cette méthode sera appelée automatiquement lors d’un changement d’état de la classe observée.

- L'interface Observable devra être implémentée par les classes désireuses de posséder des observateurs. La classe ObservableConcret implémente cette interface, ce qui lui permet de tenir informés ses observateurs. Celle-ci possède en attribut un état (ou plusieurs) et un tableau d’observateurs. L’état est un attribut dont les observateurs désirent suivre l’évolution de ses valeurs. Le tableau d’observateurs correspond à la liste des observateurs qui sont à l’écoute.

- Il ne suffit pas à une classe d’implémenter l’interface Observateur pour être à l’écoute, il faut qu’elle s’abonne à un Observable via la méthode ajouterObservateur(Observateur).

(34)

34

Patrons d'architecture

Le modèle MVC (Modèle Vue Contrôleur)

- Dans les interfaces graphiques, il est préférable de séparer les données manipulées et l'affichage de ces données.

- Ce design pattern a tendance à multiplier le nombre de classes à définir et semble alourdir la conception d’application, mais le découplage ainsi obtenu assure une maintenance facilitée.

Modèle: gère les données et reprend la logique métier (le modèle lui-même peut être décomposé en plusieurs couches mais cette décomposition n'intervient pas au niveau de MVC). Le modèle ne prend en compte aucun élément de présentation!

Vue: elle affiche les données, provenant exclusivement du modèle, pour l'utilisateur et/ou reçoit ses actions. Aucun traitement – autre que la gestion de présentation - n'y est réalisé.

Contrôleur: son rôle est de traiter les événements en provenance de l’interface utilisateur et les transmet au modèle pour le faire évoluer ou à la vue pour modifier son aspect visuel (pas de modification des données affichées mais des modifications de présentation (couleur de fond, affichage ou non de la légende d’un graphique, ... ).

(35)

- Le contrôleur connaît la (les) vues qu’il contrôle ainsi que le modèle.

- Il pourra appeler des méthodes du modèle pour réagir à des événements (demande d’ajout d’un client par exemple), il pourra faire modifier à la vue son aspect visuel. Il pourra aussi instancier de nouvelles vues (demande d’affichage de telle ou telle info).

- Pour faire cela, le contrôleur sera à l'écoute d'événements survenant sur les vues. La vue observera le modèle qui l'avertira du fait qu'une modification est survenue. Dans ce cas, la vue interrogera le modèle pour obtenir son nouvel état.

(36)

36

(37)

Exemple : « Counter demo »

Le programme Java CounterDemo illustre deux vues du modèle du compteur : - une vue “console”

- une seconde où le compteur s’affiche dans une fenêtre

Références

Documents relatifs

Passable : Le travail est passable ; le sujet quoique mentionné, n’est pas suffisamment développé : les concepts du cours sont très peu intégré, le texte manque de structure,

C’est pourquoi beaucoup d‘entre nous, mettent en place des ateliers philosophiques, moments bien distincts des autres moments de parole (quoi de neuf, conseil, réunions…)

Dilemme, dont la seule issue possible est d’installer une méthode evolue() dans la classe Ressource , tout en déclarant cette méthode « abstraite », c’est-à-dire sans

Les classes de conteneurs définies par la STL admettent donc toutes un paramètre template, qui, lors de l'instanciation d'un conteneur, sert

☐ Déclarons autoriser l’établissement scolaire et l’organisateur désignés ci-dessus à utiliser les photographies de notre enfant dans le cadre décrit ci-dessus. ☐

[r]

De plus, comme on souhaite d´ emontrer un r´ esultat portant sur toutes les d´ eriv´ ees successives de f, il faudra r´ eappliquer la m´ ethode dans le cadre d’un raisonnement par

La question 2 est de principe similaire aux questions 3 et 4 de l’exercice 4.16 : il s’agit de combiner l’´ egalit´ e d´ emontr´ ee via Taylor-Lagrange et les hypoth` eses de