JavaRush /Java-Blog /Random-DE /Designmuster: AbstractFactory

Designmuster: AbstractFactory

Veröffentlicht in der Gruppe Random-DE
Hallo! Heute werden wir weiterhin Designmuster studieren und über die abstrakte Fabrik sprechen . Designmuster: AbstractFactory - 1Was wir während der Vorlesung tun werden:
  • Lassen Sie uns diskutieren, was eine abstrakte Fabrik ist und welches Problem dieses Muster löst.
  • Wir erstellen das Framework einer plattformübergreifenden Anwendung zur Kaffeebestellung mit einer Benutzeroberfläche.
  • Sehen wir uns die Anweisungen zur Verwendung dieses Musters mit einem Diagramm und Code an.
  • Als Bonus ist in der Vorlesung ein Easter Egg versteckt, mit dem Sie lernen, mit Java den Namen des Betriebssystems zu ermitteln und je nach Ergebnis die eine oder andere Aktion auszuführen.
Um dieses Muster vollständig zu verstehen, müssen Sie die folgenden Themen gut verstehen:
  • Vererbung in Java;
  • abstrakte Klassen und Methoden in Java.

Welche Probleme löst das abstrakte Fabrikmuster?

Die abstrakte Fabrik hilft uns, wie alle Fabrikmuster, die Erstellung neuer Objekte richtig zu organisieren. Mit seiner Hilfe verwalten wir die „Freigabe“ verschiedener Familien miteinander verbundener Objekte. Verschiedene Familien miteinander verbundener Objekte ... Was ist das? Keine Sorge: In der Praxis ist alles einfacher, als es scheint. Beginnen wir mit der Frage, was eine Familie verwandter Objekte sein könnte. Angenommen, Sie und ich entwickeln eine Strategie, die mehrere Kampfeinheiten enthält:
  • Infanterie;
  • Kavallerie;
  • Bogenschützen.
Diese Arten von Kampfeinheiten sind miteinander verwandt, da sie in derselben Armee dienen. Wir können sagen, dass die oben aufgeführten Kategorien eine Familie miteinander verbundener Objekte sind. Das ist geklärt. Aber das abstrakte Fabrikmuster wird verwendet, um die Erstellung verschiedener Familien miteinander verbundener Objekte zu organisieren. Auch hier ist nichts Kompliziertes. Lassen Sie uns das Beispiel mit der Strategie fortsetzen. Sie haben meist mehrere unterschiedliche Gegenseiten. Die Kampfeinheiten verschiedener Seiten können sich im Aussehen erheblich unterscheiden. Die Fußsoldaten, Reiter und Bogenschützen der römischen Armee sind nicht dasselbe wie die Fußsoldaten, Reiter und Bogenschützen der Wikinger. Im Rahmen der Strategie sind Soldaten verschiedener Armeen unterschiedliche Familien miteinander verbundener Objekte. Es wäre lustig, wenn durch einen Fehler eines Programmierers ein Soldat in einer französischen Uniform aus der Zeit Napoleons und mit einer Muskete im Anschlag zwischen der römischen Infanterie herumlaufen würde. Um ein solches Problem zu lösen, ist das abstrakte Fabrikentwurfsmuster erforderlich. Nein, nicht die Probleme der Zeitreise-Peinlichkeit, sondern die Schaffung verschiedener Gruppen miteinander verbundener Objekte. Eine abstrakte Fabrik bietet eine Schnittstelle zum Erstellen aller vorhandenen Produkte (Familienobjekte). Eine abstrakte Fabrik verfügt normalerweise über mehrere Implementierungen. Jeder von ihnen ist für die Erstellung von Produkten einer der Variationen verantwortlich. Als Teil der Strategie hätten wir eine abstrakte Fabrik, die abstrakte Infanterie, Bogenschützen und Kavallerie erzeugt, sowie Implementierungen dieser Fabrik. Eine Fabrik, die römische Legionäre herstellt, und zum Beispiel eine Fabrik, die karthagische Krieger herstellt. Abstraktion ist das wichtigste Prinzip dieses Musters. Fabrikkunden arbeiten damit und mit Produkten nur über abstrakte Schnittstellen. Daher müssen wir nicht darüber nachdenken, welche Art von Kriegern wir gerade erschaffen, sondern diese Verantwortung auf eine bestimmte Implementierung der abstrakten Fabrik übertragen.

Wir automatisieren weiterhin den Coffeeshop

In der letzten Vorlesung haben wir uns mit dem Fabrikmethodenmuster befasst, mit dessen Hilfe wir das Kaffeegeschäft ausbauen und mehrere neue Kaffeeverkaufsstellen eröffnen konnten. Heute werden wir unsere Arbeit zur Modernisierung unseres Unternehmens fortsetzen. Mithilfe des abstrakten Fabrikmusters legen wir den Grundstein für eine neue Desktop-Anwendung zur Online-Kaffeebestellung. Wenn wir eine Anwendung für den Desktop schreiben, sollten wir immer an die plattformübergreifende Nutzung denken. Unsere Anwendung sollte sowohl auf macOS als auch auf Windows funktionieren (Spoiler: Linux bleibt Ihnen als Hausaufgabe überlassen). Wie wird unsere Bewerbung aussehen? Ganz einfach: Es handelt sich um ein Formular, das aus einem Textfeld, einem Auswahlfeld und einer Schaltfläche besteht. Wenn Sie Erfahrung mit verschiedenen Betriebssystemen haben, ist Ihnen sicherlich aufgefallen, dass die Schaltflächen unter Windows anders dargestellt werden als auf dem Mac. Wie alles andere auch... Also, fangen wir an. In der Rolle der Produktfamilien werden wir, wie Sie wahrscheinlich bereits verstanden haben, grafische Oberflächenelemente haben:
  • Tasten;
  • Textfelder;
  • Felder zur Auswahl.
Haftungsausschluss. Innerhalb jeder Schnittstelle könnten wir Methoden wie onClick, onValueChangedoder definieren onInputChanged. Diese. Methoden, die es uns ermöglichen, verschiedene Ereignisse zu verarbeiten (Klick auf eine Schaltfläche, Eingabe von Text, Auswahl eines Werts in einem Auswahlfeld). Auf all dies wurde bewusst verzichtet, um das Beispiel nicht zu überladen und es für das Studium des Fabrikmusters anschaulicher zu machen. Definieren wir abstrakte Schnittstellen für unsere Produkte:
public interface Button {}
public interface Select {}
public interface TextField {}
Für jedes Betriebssystem müssen wir Schnittstellenelemente im Stil dieses Betriebssystems erstellen. Wir schreiben für Windows und MacOS. Lassen Sie uns Implementierungen für Windows erstellen:
public class WindowsButton implements Button {
}

public class WindowsSelect implements Select {
}

public class WindowsTextField implements TextField {
}
Jetzt das Gleiche für MacOS:
public class MacButton implements Button {
}

public class MacSelect implements Select {
}

public class MacTextField implements TextField {
}
Großartig. Jetzt können wir unsere abstrakte Fabrik starten, die alle vorhandenen abstrakten Produkttypen erstellt:
public interface GUIFactory {

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

}
Perfekt. Wie Sie sehen, bisher nichts Kompliziertes. Dann ist alles genauso einfach. Analog zu Produkten erstellen wir für jedes Betriebssystem unterschiedliche Implementierungen unserer Fabrik. Beginnen wir mit 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();
    }
}
Zur weiteren Demonstration der Funktionsweise wurde eine Konsolenausgabe innerhalb von Methoden und Konstruktoren hinzugefügt. Jetzt für 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();
    }
}
Hinweis: Jede Methode gibt entsprechend ihrer Signatur einen abstrakten Typ zurück. Aber innerhalb der Methode schaffen wir eine konkrete Umsetzung des Produkts. Dies ist der einzige Ort, an dem wir die Erstellung bestimmter Instanzen kontrollieren. Jetzt ist es an der Zeit, die Formularklasse zu schreiben. Dies ist eine Java-Klasse, deren Felder Schnittstellenelemente sind:
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();
    }
}
Eine abstrakte Factory wird an den Formularkonstruktor übergeben, der Schnittstellenelemente erstellt. Wir übergeben die erforderliche Factory-Implementierung an den Konstruktor, damit wir Schnittstellenelemente für ein bestimmtes Betriebssystem erstellen können.
public class Application {
    private OrderCoffeeForm orderCoffeeForm;

    public void drawOrderCoffeeForm() {
        // Определим Name операционной системы, получив Bedeutung системной проперти через 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();
    }
}
Wenn wir die Anwendung unter Windows ausführen, erhalten wir die folgende Ausgabe:

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
Auf einem Mac sieht die Ausgabe wie folgt aus:

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

Unknown OS, can't draw form :( 
Nun, Sie und ich ziehen die folgende Schlussfolgerung. Wir haben ein Framework für eine GUI-Anwendung geschrieben, das genau die Oberflächenelemente erstellt, die für ein bestimmtes Betriebssystem geeignet sind. Wiederholen wir kurz, was wir erstellt haben:
  • Produktfamilie: Eingabefeld, Auswahlfeld und Button.
  • Verschiedene Implementierungen dieser Produktfamilie für Windows und macOS.
  • Eine abstrakte Fabrik, in der wir die Schnittstelle zur Erstellung unserer Produkte definiert haben.
  • Zwei Implementierungen unserer Fabrik, von denen jede für die Erstellung einer bestimmten Produktfamilie verantwortlich ist.
  • Ein Formular, eine Java-Klasse, deren Felder abstrakte Schnittstellenelemente sind, die im Konstruktor mithilfe einer abstrakten Factory mit den erforderlichen Werten initialisiert werden.
  • Anwendungsklasse. Darin erstellen wir ein Formular, mit dem wir die erforderliche Implementierung unserer Fabrik an den Konstruktor übergeben.
Insgesamt: Wir haben das abstrakte Fabrikmuster implementiert.

Abstract Factory: Gebrauchsanweisung

Abstract Factory ist ein Entwurfsmuster zur Verwaltung der Erstellung verschiedener Produktfamilien, ohne an bestimmte Produktklassen gebunden zu sein. Wenn Sie diese Vorlage verwenden, müssen Sie:
  1. Definieren Sie die Produktfamilien selbst. Nehmen wir an, wir haben zwei davon:
    • SpecificProductA1,SpecificProductB1
    • SpecificProductA2,SpecificProductB2
  2. Definieren Sie für jedes Produkt innerhalb der Familie eine abstrakte Klasse (Schnittstelle). In unserem Fall ist es:
    • ProductA
    • ProductB
  3. Innerhalb jeder Produktfamilie muss jedes Produkt die in Schritt 2 definierte Schnittstelle implementieren.
  4. Erstellen Sie eine abstrakte Fabrik mit Erstellungsmethoden für jedes in Schritt 2 definierte Produkt. In unserem Fall sind diese Methoden:
    • ProductA createProductA();
    • ProductB createProductB();
  5. Erstellen Sie Implementierungen der abstrakten Fabrik, sodass jede Implementierung die Erstellung von Produkten derselben Familie steuert. Dazu ist es notwendig, in jeder Implementierung der abstrakten Fabrik alle Erstellungsmethoden zu implementieren, damit konkrete Implementierungen von Produkten erstellt und in ihnen zurückgegeben werden.
Nachfolgend finden Sie ein UML-Diagramm, das die oben beschriebenen Anweisungen veranschaulicht: Designmuster: AbstractFactory - 3Schreiben wir nun den Code für diese Anweisung:
// Определим общие интерфейсы продуктов
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();
    }
}

Hausaufgaben

Um das Material zu festigen, können Sie zwei Dinge tun:
  1. Verbessern Sie die Kaffeebestellanwendung, damit sie unter Linux funktioniert.
  2. Erstellen Sie Ihre eigene abstrakte Fabrik, um Einheiten jeder Strategie zu produzieren. Dies kann entweder eine historische Strategie mit echten Armeen oder eine Fantasie mit Orks, Zwergen und Elfen sein. Hauptsache, Sie finden es interessant. Werden Sie kreativ, posten Sie Pins auf der Konsole und haben Sie Spaß beim Erlernen der Muster!
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION