Participer au site avec un Tip
Rechercher
 

Améliorations / Corrections

Vous avez des améliorations (ou des corrections) à proposer pour ce document : je vous remerçie par avance de m'en faire part, cela m'aide à améliorer le site.

Emplacement :

Description des améliorations :

Le design pattern « Factory Method »

Le design pattern « Singleton » Le design pattern « Abstract Factory »


Accès rapide :
Présentation du design pattern Factory Method
La représentation UML du design pattern Factory Method
Mise en oeuvre du design pattern Factory Method
Mise en oeuvre simplifiée du design pattern Singleton

Présentation du design pattern Factory Method

Ce design pattern permet de créer une instance à partir d'une classe dérivée d'un type abstrait, selon un critère donné et en vous évitant de systématiquement d'avoir à évaluer le critère de choix. La classe exacte utilisée pour produire l'objet n'est donc pas connue par l'appelant.

en français, ce motif de conception est appelé « méthode de fabrique » ou plus simplement « fabrique ».

Un exemple classique consiste à permettre la construction d'un objet d'image à partir de son nom de fichier : le problème étant que la manière de charger (ou sauvegarder) une image est dépendante de son type (gif, jpg, png...) et donc de l'extension du fichier.

La représentation UML du design pattern Factory Method

Voici un diagramme de classe UML présentant le pattern Factory Method dans sa forme originelle.

Le design pattern Factory Method.
en UML, un élément écrit en italique est considéré comme étant abstrait. Vous pourrez maintenant mieux identifier les classes et les méthodes abstraites du diagramme ci-dessus.
une fabrique étant, en général, unique dans un programme, vous pouvez coupler ce design pattern avec un design pattern singleton. C'est, plus précisément, la classe d'implémentation de la factory qui serait un singleton.

Dans les faits, les développeurs simplifient souvent le modèle en retirant l'interface de fabrique : on ne considère plus que la classe d'implémentation de la factory, qui peut aussi être un singleton.

Une simplification encore plus forte consiste à transformer la méthode de fabrique en une méthode statique directement portées par l'interface de produit (nous testerons cette variante en fin de chapitre).

Mise en oeuvre du design pattern Factory Method

Nous allons appliquer ce design pattern à la manipulation d'images, comme introduit précédemment. Je vous propose de revoir le modèle UML pour l'adapter à notre besoin : le voici.

Le design pattern Factory Method appliqué à a gestion d'images.

Commençons, tout d'abord, à nous pencher sur la définition abstraite du produit.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
 30 
package fr.koor.samples;

public abstract class Image {
    
    private String filename;

    /** Le constructeur de la classe Image */ 
    public Image(String filename) {
        this.filename = filename;
    }
    
    /** Pour récupérer le nom du fichier associé à l'image */
    public String getFilename() {
        return filename;
    }
    
    /** Permet de charger en mémoire l'image */
    public abstract void loadImage();
    
    /** Permet de sauvegarder l'image sur le disque */
    public abstract void saveImage();
    
    /** Un petit toString pour les affichages sur la console */
    @Override
    public String toString() {
        String className = this.getClass().getName();
        return className + ": Imaginez une superbe image : " + filename;
    }

}
La classe abstraire permettant de représenter le concept d'image.

Nous pouvons maintenant définir une classe dérivée pour chaque format d'images supporté par l'application.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
package fr.koor.samples;

public class ImagePng extends Image {
    
    public ImagePng(String filename) {
        super(filename);
    }

    @Override
    public void loadImage() {
        System.out.println( "Imaginez qu'on charge une image au format PNG" );
    }
    
    @Override
    public void saveImage() {
        System.out.println( "Imaginez qu'on sauvegarde une image au format PNG" );
    }

}
Une implémentation d'image supportant le format PNG.
procéder de même pour les classes ImageGif et ImageJpg.

Voici maintenant la définition de notre interface de fabrique.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
package fr.koor.samples;

public interface ImageFactory {

    Image createImage( String filename );
    
}
L'interface de fabrique

Voici maintenant la classe d'implémentation pour notre fabrique d'images.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
package fr.koor.samples;

public class ImageFactoryImpl implements ImageFactory {
    
    @Override
    public Image createImage(String filename) {
        String extention = filename.substring( filename.lastIndexOf(".") );
        Image image = switch( extention.toLowerCase() ) {
            case ".gif" -> new ImageGif( filename );
            case ".jpg" -> new ImageJpg( filename );
            case ".png" -> new ImagePng( filename );
            default -> throw new RuntimeException( "Format " + extention + " not supported" );
        };
        image.loadImage();
        return image;
    }
    
}
La classe d'implémentation pour notre fabrique d'images.

Et enfin, voici un petit exemple d'utilisation de notre « factory »

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
package fr.koor.samples;

public class Start {

    public static void main(String[] args) {
        
        ImageFactory factory = new ImageFactoryImpl();
        Image image1 = factory.createImage( "essai.png" );
        Image image2 = factory.createImage( "essai.jpg" );
        
        System.out.println( image1 );
        System.out.println( image2 );
        
    }

}
Un exemple d'utilisation.

Enfin, voici les résultats affichés par ce programme.

Imaginez qu'on charge une image au format PNG
Imaginez qu'on charge une image au format JPG
fr.koor.samples.ImagePng: Imaginez une superbe image : essai.png
fr.koor.samples.ImageJpg: Imaginez une superbe image : essai.jpg

Mise en oeuvre simplifiée du design pattern Singleton

Notez bien que dans l'exemple proposé dans la section précédente, l'interface de fabrique ne nous ait pas réellement utile et comme son implémentation ne fournit que la méthode de construction d'objet, on peut simplifier les choses en ramenant cette méthode directement sur le type Image. Voici comment vous pourriez procéder pour implémenter cette variation.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
 30 
 31 
 32 
 33 
 34 
 35 
 36 
 37 
 38 
 39 
 40 
 41 
 42 
 43 
package fr.koor.samples;

public abstract class Image {
    
    private String filename;

    /** Le constructeur de la classe Image */ 
    public Image(String filename) {
        this.filename = filename;
    }

    /** Notre factory method, sous forme de méthode statique */
    public static Image createImage(String filename) {
        String extention = filename.substring( filename.lastIndexOf(".") );
        Image image = switch( extention.toLowerCase() ) {
            case ".gif" -> new ImageGif( filename );
            case ".jpg" -> new ImageJpg( filename );
            case ".png" -> new ImagePng( filename );
            default -> throw new RuntimeException( "Format " + extention + " not supported" );
        };
        image.loadImage();
        return image;
    }
    
    /** Pour récupérer le nom du fichier associé à l'image */
    public String getFilename() {
        return filename;
    }
    
    /** Permet de charger en mémoire l'image */
    public abstract void loadImage();
    
    /** Permet de sauvegarder l'image sur le disque */
    public abstract void saveImage();
    
    /** Un petit toString pour les affichages sur la console */
    @Override
    public String toString() {
        String className = this.getClass().getName();
        return className + ": Imaginez une superbe image : " + filename;
    }

}
La classe abstraire permettant de représenter le concept d'image, portant la factory method.

Dans cette variation, nous n'avons plus besoin des fichiers ImageFactory.java et ImageFactoryImpl.java : vous pouvez les supprimer. Et voici maintenant comment invoquer notre « factory method ».

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
package fr.koor.samples;

public class Start {

    public static void main(String[] args) {
        
        Image image1 = Image.createImage( "essai.png" );
        Image image2 = Image.createImage( "essai.jpg" );
        
        System.out.println( image1 );
        System.out.println( image2 );
        
    }

}
Un exemple d'utilisation de cette seconde variation.

Les résultats produits par de nouveau main devraient être les mêmes que précédemment.



Le design pattern « Singleton » Le design pattern « Abstract Factory »