Ce document ne peut pas être employé dans le cadre d'un
cours ou d'une formation sans mon accord
Je suis formateur Java, XML tout niveau : plus de
renseignements.
(c) 2005 Alexandre Brillant
Bases
- Plus haut niveau d'abstraction dans le développement,
- Distribution de la responsabilité des classes en terme de
granularités et de relations,
- Facilité de maintenance et d'évolution du
développement,
- Réutilisation de méthodes de développement.
Catégories


Cadre
- Lorsque les classes se construisent par composition / aggregation
plutôt que par héritage.
- Analogie : Usine de fabriquation de pièce
Rôle
Déléguer le
processus de création d'objets à
une classe
1°) Abstract Factory
Rôle
Cacher la nature des objets
créés par des interfaces tout en
maintenant leurs cohérences.
Java
public interface AbstractFactory { public Engine getEngine(); public Tyre getTyre(); }
public class ConcreteFactorySNECMA implements AbstractFactory { public Engine getEngine() { return new EngineSNECMA(); } public Tyre getTyre() { return new TyreSNECMA(); } }
|
Rôle
Cacher la nature des objets
créés par des interfaces et faciliter
la conception par une règle.
Java
public interface HeXaneNodeFactory { public Node getNode( String type ); }
public class ConreteHeXaneNodeFactory implements HeXaneNodeFactory { public Node getNode( String type ) { if ( "Component".equals( type ) ) return new ComponentNode(); else if ( "Link".equals( type ) ) return new LinkNode(); else return new DefaultNode(); } }
|
Rôle
Cacher l'accès au constructeur et
maintenir un nombre limité
d'instances.
Java
public class ButtonRenderer {
private ButtonRenderer() { ... }
// Accès au singleton public static ButtonRenderer getButtonRenderer() { if ( renderer == null ) renderer = new ButtonRenderer(); return renderer; }
private static ButtonRenderer renderer; }
|
Rôle
Déléguer la construction
d'un objet sur d'autres classes.
UML
Java
public interface RepositoryBuilder { public void buildContent(); public RepositoryContent getContent(); }
public class ConcreteRepositoryBuilder implements RepositoryBuilder { public void buildContent() { files = ( new File( "." ) ).list(); }
public getContent() { return new RepositoryContent( files ); }
String[] files; }
|


Cadre
Besoin d'une structure intermédiaire de classes participant
à
une fonction. Utilisation de librairies indépendantes. Evolution
d'une composition à l'exécution.
Ex : Puzzle, jeu de cubes.
Rôle
Associer des classes pour former des
structures homogènes plus grandes
accessible par une classes.
1°) Adapter
Rôle
Permettre le support d'une nouvelle
interface
UML
Java
public interface Runnable() { public void run(); }
public class Process implements Runnable() { public void run() { ... } }
public interface Schedulable { public void run( long delay ); }
public class ProcessAdapter implements Schedulable extends Process {
public void setProcess( Process process ) { this.process = process; }
public void run() { process.run(); }
public void run( long delay ) { wait( delay ); run(); }
private Process process; }
|
Rôle
Pouvoir faire évoluer des classes
d'abstraction (ex: une fenêtre)
sans toucher au niveau implémentation (ex: une fenêtre
pour
window).
Ex : Swing (pas de peer comme dans AWT)
UML
Java
// Abstract class public class Canvas { // Set the canvas implementation for (Windows, Motif...) public void setCanvas( CanvasPeer canvas ) { this.canvas = canvas; } protected CanvasPeer canvas; public void draw() { canvas.draw(); } }
// Abstraction inheritance public class ExtendedButton extends Canvas { public void draw() { canvas.drawText( "push me" ); ... } }
|
Rôle
Pas de différentiation entre un
aggrégat d'objets et un objet.
Ex : Dans un logiciel de dessin vectoriel un groupe d'objets
lié
est un nouvel objet.
UML
Java
public class GroupComponent extends Component { public void addComponent( Component component ) { ... }
public void removeComponent( Component component ) { ... }
public void paint( Graphics gc ) { // Paint each sub component } }
|
4°) Decorator
Rôle
Pouvoir enrichir dynamiquement la
représentation graphique d'un objet.
Ex : Border swing
Java
// Decorator for any rendering public class ExtendedRenderer extends Renderer { public void addRenderer( Renderer renderer ) { ... }
public void removeRenderer( Renderer renderer ) { ... }
public void paint( Grapics gc ) { // Paint all renderer ... } }
|
Rôle
Regrouper les intéractions avec
une API dans une classe ou façade.
UML
Java
// Facade for the dynamix API public class DynamixFacade { // Merge data and the model to produce output public void transform( Hashtable data, String model, String output ) { ... } }
|
Rôle
Minimiser le nombre d'instance and
distinguant deux états dans un
objet :
- Etat personnel ( lié à chaque objet )
- Etat global ( indépendant de l'objet )
Ex : Caractères dans un traitement de texte, avec le code
ASCII
pour l'état personnel et la position du caractère pour
l'état
global.
UML
Java
public class CaracterView extends View { public void draw() { ... }
// Personal state char c; }
public void Editor { public void initCars() { ... // Reset carView for all caracters once }
public void addCaracterView( char c ) { cars.addElement( carView.get( c ) ); }
public void draw() { // Compute the global state
// Paint using cars View }
Hashtable carView = new Hastable(); Vector cars = new Vector(); }
|
Rôle
Objet supplémentaire jouant le
rôle d'un autre objet. Types
de proxy :
- Remote proxy, (stub rmi, corba...)
- Virtual proxy, (extension d'un objet dynamique)
- Protection proxy, (contrôle de l'accès à un
objet)
- Smart proxy. (instance avec compteur pour le garbage collector)
UML
Java
// Share interface client/server public interface Action { public void doAction(); }
// Remote action (on server) public class ConcreteAction implements Action { public void doAction() { ... } }
// Client proxy public class ActionStub implements Action {
public void doAction() { // Send Tcp/Ip order for calling remote doAction } }
|


Cadre
Des traitements différents se font en fonction d'un contexte.
Ex : Contrôleur Java (sur button et checkbox)
Rôle
Limiter les responsabilités des
traitements à certaines classes.
Contrôler les flux de traitements.
1°) Chain of responsability
Rôle
Définir une arborescence de
traitement.
Ex: Une info-bulle est affichée sur certains boutons, sinon
c'est l'info-bulle du conteneur qui est affiché.
UML
Java
// Decide to handle public interface Handler { public boolean handle( Context context ); public void handler(); }
// List of handlers public void HandlerManager {
public void addHandler( Handler handler ) {}
public void handle() { // search the first handler and launch it } }
|
Rôle
Déléguer un traitement sur
une autre classe.
Ex : Contrôleur java
UML
Java
myButton.addActionListener( myControleur );
Rôle
Offrir un mini - interpréteur
syntaxique et permettre l'utilisation
de commandes avec un language adapté.
Ex : Expressions régulières (^a|(b?c*)) pour a b
bcccc...
cccc...
L'idée est d'accocier à une grammaire une classe et de
construire
par des instances l'arbre de syntaxe abstrait (premier arbre produit
par
la compilation). Ces instances sont ensuite parcourues pour valider /
exécuter la commande.
Pour des grammaires complexes les outils de conversion automatiques
sont indispensables (équivallent lex/yacc javacc).
UML
Java
lettre ::= 'a', 'b', 'c' lettres ::= {} | lettre lettres expression ::= '(' expression ')' | lettres
// Letter rule public class Letter implements Interpretable { public void interpret( Context context ) throws Exception { char c = context.nextInput(); if ( c == 'a' | c == 'b' | c == 'c' ) letter = c; else throws Exception( "Invalid input :" + c ); } private char letter; }
// Letters rule public class Letters implements Interpretable { public void interpret( Context context ) throws Exception { for ( int i = 0; i < letters.size(); i++ ) { ( (Letter)( letters.elementAt( i ) ) ).interpret( context ); } } // Add a new letters public void addLetter( Letter letter ) { letters.addElement( letter ); } private Vector letters = new Vector(); }
// Expression rule public class Expression implements Interpretable { public void interpret( Context context ) throws Exception { char c = context.nextInput(); if ( expression != null ) { if ( c == '(' ) { expression.interpret( context ); if ( context.nextInput() != ')' ) throws Exception( "Invalid parenthesis" ); } } else letters.interpret( context ); }
public void setLetters( Letters letters ) { this.letters = letters; }
public void setExpression( Expression expression ) { expression = expression; }
private Letters letters; private Expression expression; }
// Instance to interpret (ab)
Letter a = new Letter( 'a' ); Letter b = new Letter( 'b' ); Letters l = new Letters(); l.addLetter( a ); l.addLetter( b ); Expression e1 = new Expression(); e1.setLetters( l ); Expression e2 = new Expression(); e2.setExpression( e1 );
e2.interpret( new Context( "(ab)" ) );
|
Rôle
Pouvoir accéder au contenu
séquentiel d'une collection sans
connaître le système de stockage.
Ex : Enumeration sur Vector / Hashtable
UML
Java
// Client iterator public interface Iterator { public Object first(); public Object next(); public boolean hasMoreElements(); e }
// Data structure with object array public ArrayData { public ArrayIterator( Object[] array ) { this.array = array; }
public Iterator getIterator() { return new Iterator() { public boolean hasMoreElements() { return i < array.length; }
public Object first() { return array[ i = 0 ]; } public Object next() { return array[ i++ ]; } int i; }; }
private Object[] array; }
|
Rôle
Lorsque trop d'intéraction
existent entre objets, les stocker dans
un contrôleur spécifique.
Ex : Une liste avec un champ texte. Lorsque un caractère est
entré
dans le champ texte, la liste se met à jour, lorsque une
sélection
est faite dans la liste, le champ texte se met à jour.
UML
Java
// Interaction between two buttons public class Mediator implements ActionListener { public void setButton1( Button button1 ) { this.button1 = button1; button1.addActionListener( this ); }
public void setButton2( Button button2 ) { this.button2 = button2; button2.addActionListener( this ); }
public void actionPerformed( ActionEvent evt ) { if ( evt.getSource() == button1 ) { button2.setText( button1.getText() ); } else button1.setText( button2.getText() ); }
private Button button1, button2; }
|
Rôle
Pouvoir stocker/restaurer l'état
d'un objet.
Ex : Swing avec sérialization XML (transformation
swing->xml
/ xml->swing).
UML
Java
public class BooleanState { public BooleanState( boolean state ) { this.state = state; }
public boolean isActive() { return state; }
boolean state; }
public class Boolean { public void setState( BooleanState state ) { value = state.isActive; }
public void getState() { return new BooleanState( state ); }
boolean value; }
|
Rôle
Informer un objet d'un changement dans
un autre sans créer de liaison
explicite.
Ex : Une feuille excel est mise à jour, différents
graphes
se rafraîchissent.
UML
Java
// Observable button that notify observer for click public class ButtonObservable {
public ButtonObservable() { super(); addActionListener( this ); }
public void addObserver( Observer observer ) { observable.addObserver( observer ); }
public void actionPerformed( ActionEvent evt ) { observable.notifyObservers(); }
Observable observable = new Observable(); }
|
Rôle
Obtenir des traitements en fonction de
l'état courant.
UML
Java
public interface TCPState { public void open(); public void close(); public void listen(); }
public interface TCPOpen extends TCPState { }
public interface TCPListen extends TCPState { }
public interface TCPClose extends TCPState { }
public class TCPHandler {
public void open() { state.open(); }
public void close() { state.close(); }
public void listen() { state.listen(); }
public void setState( TCPState state ) { this.state = state; }
public TCPState state; }
|
Rôle
Plus vaste que le pattern "state",
permet de choisir un algorithme adapté
au contexte.
UML
Java
public class IndentDocument { public void setIndenter( Indenter indenter );
// Depend on the context public void indent( Document doc ) { indenter.indent( doc ); } }
// Indent document strategy public interface Indenter { public void indent( Document doc ); }
|
Rôle
Définir le squelette d'un
algorithme et déléguer certaines
actions aux sous-classes.
Ex : Trier une liste d'objet. L'algorithme de tri
délègue
la comparaison des objets.
UML
Java
public abstract class Sorter {
// Template method public void sort( Object[] data ) { for ( int i = 0; i < data.length; i++ ) { int min = i; for ( int j = 1; j < data.length; j++ ) { if ( isSmallerThan( data[ min ], data[ j ] ) ) min = j; } Object tmp = data[ i ]; data[ i ] = data[ min ]; data[ min ] = tmp; } }
public abstract boolean isSmallerThan( Object data1, Object data2 ); }
|
Rôle
Lors du parcours d'une structure,
pouvoir concentrer les actions hors de
l'élément de la structure.
UML
Java
public interface Visitor { public void actionForAllNode( Node node ); public void actionForCustomNode( CustomNode node ); }
public class Node { public void accept( Visitor visitor ) { visitor.actionForAllNode( this ); } }
public class CustomNode extends Node { public void accept( Visitor visitor ) { visitor.actionForCustomNode( this ); } }
|
Le design pattern oblige le développeur à segmenter
son
programme en fonctionnalités qu'il peut ensuite faire
évoluer
sans modifier l'architecture globale de l'application.