JavaRush /Blog Java /Random-FR /Modèles de conception : AbstractFactory

Modèles de conception : AbstractFactory

Publié dans le groupe Random-FR
Bonjour! Aujourd'hui, nous continuerons à étudier les modèles de conception et à parler de l'usine abstraite . Modèles de conception : AbstractFactory - 1Ce que nous ferons pendant la conférence :
  • Discutons de ce qu'est une usine abstraite et du problème que ce modèle résout ;
  • nous créerons le cadre d'une application multiplateforme pour commander du café avec une interface utilisateur ;
  • Étudions les instructions d'utilisation de ce modèle avec un diagramme et un code ;
  • En prime, il y a un œuf de Pâques caché dans la conférence, grâce auquel vous apprendrez à déterminer le nom du système d'exploitation utilisant Java et, en fonction du résultat, à effectuer l'une ou l'autre action.
Pour bien comprendre ce modèle, vous devez avoir une bonne compréhension des sujets suivants :
  • héritage en Java ;
  • classes et méthodes abstraites en Java.

Quels problèmes le modèle d’usine abstrait résout-il ?

L’usine abstraite, comme tous les modèles d’usine, nous aide à organiser correctement la création de nouveaux objets. Avec son aide, nous gérons la « libération » de différentes familles d'objets interconnectés. Différentes familles d'objets interdépendants... Qu'est-ce que c'est ? Ne vous inquiétez pas : en pratique, tout est plus simple qu'il n'y paraît. Commençons par ce que pourrait être une famille d’objets liés ? Supposons que vous et moi développions une stratégie et qu'elle contienne plusieurs unités de combat :
  • infanterie;
  • cavalerie;
  • archers.
Ces types d’unités de combat sont liées les unes aux autres car elles servent dans la même armée. On peut dire que les catégories énumérées ci-dessus constituent une famille d'objets interdépendants. C'est réglé. Mais le modèle abstrait de l’usine est utilisé pour organiser la création de diverses familles d’objets interconnectés. Rien de compliqué ici non plus. Continuons l'exemple avec la stratégie. Ils ont généralement plusieurs camps opposés. Les unités de combat des différents camps peuvent différer 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 des Vikings. Dans le cadre de la stratégie, les soldats des différentes armées constituent différentes familles d’objets interconnectés. Ce serait drôle si, par erreur d’un programmeur, un soldat en uniforme français de l’époque de Napoléon, un mousquet à la main, se promenait parmi l’infanterie romaine. C’est pour résoudre un tel problème que le modèle de conception abstrait de l’usine est nécessaire. Non, pas les problèmes liés à l'embarras du voyage dans le temps, mais la création de divers groupes d'objets interconnectés. Une usine abstraite fournit une interface pour créer tous les produits existants (objets familiaux). Une usine abstraite a généralement plusieurs implémentations. Chacun d’eux est responsable de la création de produits d’une des variantes. Dans le cadre de la stratégie, nous aurions une usine abstraite qui créerait de l'infanterie, des archers et de la cavalerie abstraits, ainsi que des implémentations de cette usine. Une usine qui crée des légionnaires romains et, par exemple, une usine qui crée des guerriers carthaginois. L'abstraction est le principe le plus important de ce modèle. Les clients Factory travaillent avec lui et avec les produits uniquement via des interfaces abstraites. Par conséquent, nous n’avons pas besoin de réfléchir au type de guerriers que nous créons actuellement, mais de transférer cette responsabilité à une implémentation spécifique de l’usine abstraite.

Nous continuons à automatiser le café

Lors de la dernière conférence, nous avons étudié le modèle de méthode d'usine, grâce auquel nous avons pu développer le commerce du café et ouvrir plusieurs nouveaux points de vente de café. Aujourd'hui, nous allons poursuivre notre travail de modernisation de notre entreprise. En utilisant le modèle d'usine abstrait, nous poserons les bases d'une nouvelle application de bureau permettant de commander du café en ligne. Lorsque nous écrivons une application pour le bureau, nous devons toujours penser au multiplateforme. Notre application devrait fonctionner à la fois sur macOS et Windows (spoiler : Linux vous sera laissé en devoir). À quoi ressemblera notre candidature ? 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 sous Windows, les boutons sont rendus différemment que sur Mac. Comme tout le reste... Alors, commençons. Dans le rôle des familles de produits, comme vous l'avez probablement déjà compris, nous aurons des éléments d'interface graphique :
  • boutons;
  • champs de texte ;
  • champs de sélection.
Clause de non-responsabilité. Dans chaque interface, nous pourrions définir des méthodes telles que onClick, onValueChangedou onInputChanged. Ceux. des méthodes qui nous permettront de gérer divers événements (cliquer sur un bouton, saisir du texte, sélectionner une valeur dans une zone de sélection). Tout cela est volontairement omis afin de ne pas surcharger l'exemple et de le rendre plus visuel pour 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 de ce système d'exploitation. Nous écrivons 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, pareil pour MacOS :
public class MacButton implements Button {
}

public class MacSelect implements Select {
}

public class MacTextField implements TextField {
}
Super. Nous pouvons maintenant démarrer notre usine abstraite, qui créera tous les types de produits abstraits existants :
public interface GUIFactory {

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

}
Parfait. Comme vous pouvez le constater, rien de compliqué jusqu’à présent. Ensuite, tout est tout aussi simple. Par analogie avec les produits, nous créons différentes implémentations de notre usine pour chaque OS. Commençons par Windows :
public class WindowsGUIFactory implements GUIFactory {
    public WindowsGUIFactory() {
        System.out.println("Creating gui factory 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();
    }
}
La sortie de la console dans les méthodes et les constructeurs a été ajoutée pour démontrer davantage son fonctionnement. Maintenant pour macOS :
public class MacGUIFactory implements GUIFactory {
    public MacGUIFactory() {
        System.out.println("Creating gui factory 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();
    }
}
Remarque : chaque méthode, selon sa signature, renvoie un type abstrait. Mais à l’intérieur de la méthode, nous créons une mise en œuvre concrète du produit. C'est le seul endroit où nous contrôlons la création d'instances spécifiques. Il est maintenant temps d'écrire la classe form. Il s'agit d'une classe Java dont les champs sont des éléments d'interface :
public class OrderCoffeeForm {
    private final TextField customerNameTextField;
    private final Select coffeTypeSelect;
    private final Button orderButton;

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

    public void drawOrderCoffeeForm() {
        // Определим Name операционной системы, получив meaning системной проперти через System.getProperty
        String osName = System.getProperty("os.name").toLowerCase();
        GUIFactory guiFactory;

        if (osName.startsWith("win")) { // Для windows
            guiFactory = new WindowsGUIFactory();
        } else if (osName.startsWith("mac")) { // Для mac
            guiFactory = new MacGUIFactory();
        } else {
            System.out.println("Unknown OS, can't draw form :( ");
            return;
        }
        orderCoffeeForm = new OrderCoffeeForm(guiFactory);
    }

    public static void main(String[] args) {
        Application application = new Application();
        application.drawOrderCoffeeForm();
    }
}
Si nous exécutons l'application sous Windows, nous obtiendrons le résultat suivant :

Creating gui factory for Windows OS
Creating order coffee form
Creating TextField for Windows OS
Creating Select for Windows OS
Creating Button for Windows OS
Sur un Mac, le résultat sera le suivant :

Creating gui factory for macOS
Creating order coffee form
Creating TextField for macOS
Creating Select for macOS
Creating Button for macOS
Sous Linux :

Unknown OS, can't draw form :( 
Eh bien, vous et moi tirons la conclusion suivante. Nous avons écrit un framework pour une application GUI qui crée exactement les éléments d'interface appropriés pour un système d'exploitation donné. Répétons brièvement ce que nous avons créé :
  • Famille de produits : champ de saisie, champ de sélection et bouton.
  • Diverses implémentations de cette famille de produits, pour Windows et macOS.
  • Une usine abstraite, au sein de laquelle nous avons défini l'interface de création de nos produits.
  • Deux implémentations de notre usine, chacune étant chargée de créer 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 dans le constructeur avec les valeurs requises à l'aide d'une usine abstraite.
  • Classe d'application. À l'intérieur, nous créons un formulaire avec lequel nous transmettons l'implémentation requise de notre usine au constructeur.
Total : nous avons implémenté le modèle d'usine abstraite.

Usine abstraite : mode d’emploi

Abstract Factory 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 spécifiques. Lorsque vous utilisez ce modèle, vous devez :
  1. Définir eux-mêmes les 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 c'est :
    • 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 de création pour chaque produit défini à l'étape 2. Dans notre cas, ces méthodes seront :
    • ProductA createProductA();
    • ProductB createProductB();
  5. Créez des implémentations de la fabrique abstraite afin que chaque implémentation contrôle la création de produits de la même famille. Pour ce faire, à l'intérieur de chaque implémentation de la fabrique abstraite, il est nécessaire d'implémenter toutes les méthodes de création, afin que des implémentations concrètes de produits soient créées et renvoyées à l'intérieur.
Vous trouverez ci-dessous un diagramme UML illustrant les instructions décrites ci-dessus : Modèles de conception : AbstractFactory - 3Écrivons maintenant le code de cette instruction :
// Определим общие интерфейсы продуктов
public interface ProductA {}
public interface ProductB {}

// Создадим различные реализации (семейства) наших продуктов
public class SpecificProductA1 implements ProductA {}
public class SpecificProductB1 implements ProductB {}

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

// Создадим абстрактную фабрику
public interface AbstractFactory {
    ProductA createProductA();
    ProductB createProductB();
}

// Создадим реализацию абстрактной фабрики для создания продуктов семейства 1
public class SpecificFactory1 implements AbstractFactory {

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

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

// Создадим реализацию абстрактной фабрики для создания продуктов семейства 1
public class SpecificFactory2 implements AbstractFactory {

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

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

Devoirs

Pour consolider le matériel, vous pouvez faire 2 choses :
  1. Améliorez l'application de commande de café pour qu'elle fonctionne sous Linux.
  2. Créez votre propre usine abstraite pour produire des unités de n'importe quelle stratégie. Cela peut être soit une stratégie historique avec de vraies armées, soit une stratégie fantastique avec des orcs, des nains et des elfes. L'essentiel est que vous trouviez cela intéressant. Faites preuve de créativité, publiez des épingles sur la console et amusez-vous à apprendre les modèles !
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION