CodeGym/Blog Java/Random-FR/Motifs de conception : Usine abstraite
Auteur
Alex Vypirailenko
Java Developer at Toshiba Global Commerce Solutions

Motifs de conception : Usine abstraite

Publié dans le groupe Random-FR
membres
Salut! Aujourd'hui, nous allons continuer à étudier les modèles de conception et nous discuterons du modèle d'usine abstraite . Motifs de conception : Usine abstraite - 1Voici ce que nous allons couvrir dans la leçon :
  • Nous discuterons de ce qu'est une usine abstraite et du problème que ce modèle résout
  • Nous allons créer le squelette d'une application multiplateforme pour commander du café via une interface utilisateur
  • Nous étudierons des instructions sur la façon d'utiliser ce modèle, y compris en regardant un diagramme et un code
  • Et en prime, cette leçon comprend un œuf de Pâques caché qui vous aidera à apprendre à utiliser Java pour déterminer le nom du système d'exploitation et, selon le résultat, à effectuer une autre action ou une autre.
Pour bien comprendre ce modèle, vous devez bien connaître les sujets suivants :
  • héritage en Java
  • classes abstraites et méthodes en Java

Quels problèmes une usine abstraite résout-elle ?

Une usine abstraite, comme tous les modèles d'usine, nous aide à nous assurer que de nouveaux objets sont créés correctement. Nous l'utilisons pour gérer la "production" de différentes familles d'objets interconnectés. Diverses familles d'objets interconnectés... Qu'est-ce que cela signifie ? Rassurez-vous : en pratique, tout est plus simple qu'il n'y paraît. Pour commencer, que pourrait être une famille d'objets interconnectés ? Supposons que nous développions une stratégie militaire impliquant plusieurs types d'unités :
  • infanterie
  • cavalerie
  • archers
Ces types d'unités sont interconnectés, car ils servent dans la même armée. On pourrait dire que les catégories énumérées ci-dessus sont une famille d'objets interconnectés. Nous comprenons cela. Mais le modèle d'usine abstraite est utilisé pour organiser la création de diverses familles d'objets interconnectés. Il n'y a rien de compliqué ici non plus. Continuons avec l'exemple de la stratégie militaire. D'une manière générale, les unités militaires appartiennent à plusieurs parties belligérantes différentes. Selon le camp où elles se trouvent, les unités militaires peuvent varier considérablement en apparence. Les fantassins, cavaliers et archers de l'armée romaine ne sont pas les mêmes que les fantassins, cavaliers et archers vikings. Dans la stratégie militaire, les soldats de différentes armées sont différentes familles d'objets interconnectés. Ce serait drôle si un programmeur' Par erreur, un soldat en uniforme français de l'époque napoléonienne, mousquet au poing, se retrouve dans les rangs de l'infanterie romaine. Le modèle de conception d'usine abstrait est précisément nécessaire pour résoudre ce problème. Non, pas le problème de l'embarras qui peut provenir du voyage dans le temps, mais le problème de la création de divers groupes d'objets interconnectés. Une usine abstraite fournit une interface pour créer tous les produits disponibles (une famille d'objets). Une usine abstraite a généralement plusieurs implémentations. Chacun d'eux est responsable de la création des produits d'une des familles. Notre stratégie militaire inclurait une usine abstraite qui crée des fantassins, des archers et des cavaliers abstraits, ainsi que des implémentations de cette usine. Par exemple, une usine qui crée des légionnaires romains et une usine qui crée des soldats carthaginois. L'abstraction est le principe directeur le plus important de ce modèle. Les clients de l'usine ne travaillent avec l'usine et ses produits qu'à travers des interfaces abstraites. En conséquence, vous n'avez pas à penser aux soldats qui sont actuellement créés. Au lieu de cela, vous transférez cette responsabilité à une implémentation concrète de l'usine abstraite.

Continuons à automatiser notre café

Dans la dernière leçon, nous avons étudié le modèle de méthode d'usine. Nous l'avons utilisé pour développer notre activité de café et ouvrir plusieurs nouveaux sites. Aujourd'hui, nous allons continuer à moderniser notre entreprise. En utilisant le modèle d'usine abstraite, nous allons jeter les bases d'une nouvelle application de bureau pour commander du café en ligne. Lors de l'écriture d'une application de bureau, nous devons toujours penser au support multiplateforme. Notre application doit fonctionner à la fois sur macOS et Windows (spoiler : la prise en charge de Linux est laissée à votre devoir). A quoi ressemblera notre application ? Assez simple : ce sera un formulaire composé d'un champ de texte, d'un champ de sélection et d'un bouton. Si vous avez de l'expérience avec différents systèmes d'exploitation, vous avez certainement remarqué que les boutons sous Windows sont rendus différemment que sur un Mac. Comme tout le reste... Eh bien, commençons.
  • boutons
  • champs de texte
  • champs de sélection
Avis de non-responsabilité : dans chaque interface, nous pourrions définir des méthodes telles que onClick, onValueChangedou onInputChanged. En d'autres termes, nous pourrions définir des méthodes qui nous permettront de gérer divers événements (appuyer sur un bouton, saisir du texte, sélectionner une valeur dans une boîte de sélection). Tout ceci est volontairement omis ici afin de ne pas surcharger l'exemple et de le rendre plus clair au fur et à mesure de l'étude du modèle d'usine. Définissons des interfaces abstraites pour nos produits :
public interface Button {}
public interface Select {}
public interface TextField {}
Pour chaque système d'exploitation, nous devons créer des éléments d'interface dans le style du système d'exploitation. Nous allons écrire du code pour Windows et MacOS. Créons des implémentations pour Windows :
public class WindowsButton implements Button {
}

public class WindowsSelect implements Select {
}

public class WindowsTextField implements TextField {
}
Maintenant, nous faisons la même chose pour MacOS :
public class MacButton implements Button {
}

public class MacSelect implements Select {
}

public class MacTextField implements TextField {
}
Excellent. Nous pouvons maintenant passer à notre usine abstraite, qui créera tous les types de produits abstraits disponibles :
public interface GUIFactory {

    Button createButton();
    TextField createTextField();
    Select createSelect();

}
Superbe. Comme vous pouvez le voir, nous n'avons encore rien fait de compliqué. Tout ce qui suit est également simple. Par analogie avec les produits, nous créons différentes implémentations d'usine pour chaque OS. Commençons par Windows :
public class WindowsGUIFactory implements GUIFactory {
    public WindowsGUIFactory() {
        System.out.println("Creating GUIFactory for Windows OS");
    }

    public Button createButton() {
        System.out.println("Creating Button for Windows OS");
        return new WindowsButton();
    }

    public TextField createTextField() {
        System.out.println("Creating TextField for Windows OS");
        return new WindowsTextField();
    }

    public Select createSelect() {
        System.out.println("Creating Select for Windows OS");
        return new WindowsSelect();
    }
}
Nous avons ajouté une sortie de console à l'intérieur des méthodes et du constructeur afin d'illustrer davantage ce qui se passe. Maintenant pour macOS :
public class MacGUIFactory implements GUIFactory {
    public MacGUIFactory() {
        System.out.println("Creating GUIFactory for macOS");
    }

    @Override
    public Button createButton() {
        System.out.println("Creating Button for macOS");
        return new MacButton();
    }

    @Override
    public TextField createTextField() {
        System.out.println("Creating TextField for macOS");
        return new MacTextField();
    }

    @Override
    public Select createSelect() {
        System.out.println("Creating Select for macOS");
        return new MacSelect();
    }
}
Notez que chaque signature de méthode indique que la méthode renvoie un type abstrait. Mais à l'intérieur des méthodes, nous créons des implémentations spécifiques des produits. C'est le seul endroit où nous contrôlons la création d'instances spécifiques. Il est maintenant temps d'écrire une classe pour le formulaire. Il s'agit d'une classe Java dont les champs sont des éléments d'interface :
public class CoffeeOrderForm {
    private final TextField customerNameTextField;
    private final Select coffeeTypeSelect;
    private final Button orderButton;

    public CoffeeOrderForm(GUIFactory factory) {
        System.out.println("Creating coffee order form");
        customerNameTextField = factory.createTextField();
        coffeeTypeSelect = factory.createSelect();
        orderButton = factory.createButton();
    }
}
Une fabrique abstraite qui crée des éléments d'interface est transmise au constructeur du formulaire. Nous transmettrons l'implémentation d'usine nécessaire au constructeur afin de créer des éléments d'interface pour un système d'exploitation particulier.
public class Application {
    private CoffeeOrderForm coffeeOrderForm;

    public void drawCoffeeOrderForm() {
        // Determine the name of the operating system through System.getProperty()
        String osName = System.getProperty("os.name").toLowerCase();
        GUIFactory guiFactory;

        if (osName.startsWith("win")) { // For Windows
            guiFactory = new WindowsGUIFactory();
        } else if (osName.startsWith("mac")) { // For Mac
            guiFactory = new MacGUIFactory();
        } else {
            System.out.println("Unknown OS. Unable to draw form :(");
            return;
        }
        coffeeOrderForm = new CoffeeOrderForm(guiFactory);
    }

    public static void main(String[] args) {
        Application application = new Application();
        application.drawCoffeeOrderForm();
    }
}
Si nous exécutons l'application sous Windows, nous obtenons le résultat suivant :
Creating GUIFactory for Windows OS
Creating coffee order form
Creating TextField for Windows OS
Creating Select for Windows OS
Creating Button for Windows OS
Sur un Mac, la sortie sera la suivante :
Creating GUIFactory for macOS
Creating coffee order form
Creating TextField for macOS
Creating Select for macOS
Creating Button for macOS
Sous Linux :
Unknown OS. Unable to draw form :(
Et maintenant on résume. Nous avons écrit le squelette d'une application basée sur une interface graphique dans laquelle les éléments d'interface sont créés spécifiquement pour le système d'exploitation concerné. Nous allons répéter de manière concise ce que nous avons créé :
  • Une famille de produits composée d'un champ de saisie, d'un champ de sélection et d'un bouton.
  • Différentes implémentations de la famille de produits pour Windows et macOS.
  • Une usine abstraite qui définit une interface pour créer nos produits.
  • Deux implémentations de notre usine, chacune responsable de la création d'une famille spécifique de produits.
  • Un formulaire (une classe Java) dont les champs sont des éléments d'interface abstraits qui sont initialisés avec les valeurs nécessaires dans le constructeur à l'aide d'une usine abstraite.
  • Classe d'application Dans cette classe, nous créons un formulaire, en passant l'implémentation d'usine souhaitée à son constructeur.
Le résultat est que nous avons implémenté le modèle d'usine abstraite.

Usine abstraite : mode d'emploi

Une usine abstraite est un modèle de conception permettant de gérer la création de différentes familles de produits sans être lié à des classes de produits concrètes. Lorsque vous utilisez ce modèle, vous devez :
  1. Définir des familles de produits. Supposons que nous en ayons deux :
    • SpecificProductA1,SpecificProductB1
    • SpecificProductA2,SpecificProductB2
  2. Pour chaque produit de la famille, définissez une classe abstraite (interface). Dans notre cas, nous avons :
    • ProductA
    • ProductB
  3. Au sein de chaque famille de produits, chaque produit doit implémenter l'interface définie à l'étape 2.
  4. Créez une usine abstraite, avec des méthodes pour créer chaque produit défini à l'étape 2. Dans notre cas, ces méthodes seront :
    • ProductA createProductA();
    • ProductB createProductB();
  5. Créez des implémentations d'usines abstraites afin que chaque implémentation contrôle la création de produits d'une seule famille. Pour ce faire, à l'intérieur de chaque implémentation de la fabrique abstraite, vous devez implémenter toutes les méthodes de création afin qu'elles créent et renvoient des implémentations de produit spécifiques.
Le diagramme UML suivant illustre les instructions décrites ci-dessus : Design patterns : Usine abstraite - 3Nous allons maintenant écrire du code conformément à ces instructions :
// Define common product interfaces
public interface ProductA {}
public interface ProductB {}

// Create various implementations (families) of our products
public class SpecificProductA1 implements ProductA {}
public class SpecificProductB1 implements ProductB {}

public class SpecificProductA2 implements ProductA {}
public class SpecificProductB2 implements ProductB {}

// Create an abstract factory
public interface AbstractFactory {
    ProductA createProductA();
    ProductB createProductB();
}

// Implement the abstract factory in order to create products in family 1
public class SpecificFactory1 implements AbstractFactory {

    @Override
    public ProductA createProductA() {
        return new SpecificProductA1();
    }

    @Override
    public ProductB createProductB() {
        return new SpecificProductB1();
    }
}

// Implement the abstract factory in order to create products in family 2
public class SpecificFactory2 implements AbstractFactory {

    @Override
    public ProductA createProductA() {
        return new SpecificProductA2();
    }

    @Override
    public ProductB createProductB() {
        return new SpecificProductB2();
    }
}

Devoirs

Pour renforcer le matériau, vous pouvez faire 2 choses :
  1. Affinez l'application de commande de café pour qu'elle fonctionne également sous Linux.
  2. Créez votre propre usine abstraite pour produire des unités impliquées dans n'importe quelle stratégie militaire. Cela peut être soit une stratégie militaire historique impliquant de vraies armées, soit une stratégie fantastique avec des orcs, des gnomes et des elfes. L'important est de choisir quelque chose qui vous intéresse. Soyez créatif, imprimez des messages sur la console et amusez-vous à apprendre les motifs !
Commentaires
  • Populaires
  • Nouveau
  • Anciennes
Tu dois être connecté(e) pour laisser un commentaire
Cette page ne comporte pas encore de commentaires