CodeGym/Java-Blog/Random-DE/Designmuster: Abstrakte Fabrik
Autor
Alex Vypirailenko
Java Developer at Toshiba Global Commerce Solutions

Designmuster: Abstrakte Fabrik

Veröffentlicht in der Gruppe Random-DE
Hallo! Heute werden wir uns weiterhin mit Designmustern befassen und das abstrakte Fabrikmuster diskutieren . Designmuster: Abstrakte Fabrik – 1Folgendes werden wir in der Lektion behandeln:
  • Wir werden diskutieren, was eine abstrakte Fabrik ist und welches Problem dieses Muster löst
  • Wir erstellen das Grundgerüst einer plattformübergreifenden Anwendung zum Bestellen von Kaffee über eine Benutzeroberfläche
  • Wir werden Anweisungen zur Verwendung dieses Musters studieren, einschließlich der Betrachtung eines Diagramms und eines Codes
  • Und als Bonus enthält diese Lektion ein verstecktes Easter Egg, mit dem Sie lernen, wie Sie mit Java den Namen des Betriebssystems ermitteln und je nach Ergebnis die eine oder andere Aktion ausführen.
Um dieses Muster vollständig zu verstehen, müssen Sie sich mit den folgenden Themen auskennen:
  • Vererbung in Java
  • abstrakte Klassen und Methoden in Java

Welche Probleme löst eine abstrakte Fabrik?

Eine abstrakte Fabrik hilft uns, wie alle Fabrikmuster, sicherzustellen, dass neue Objekte korrekt erstellt werden. Wir nutzen es, um die „Produktion“ verschiedener Familien miteinander verbundener Objekte zu verwalten. Verschiedene Familien miteinander verbundener Objekte... Was bedeutet das? Keine Sorge: In der Praxis ist alles einfacher, als es scheint. Was könnte zunächst einmal eine Familie miteinander verbundener Objekte sein? Angenommen, wir entwickeln eine Militärstrategie mit mehreren Arten von Einheiten:
  • Infanterie
  • Kavallerie
  • Bogenschützen
Diese Einheitentypen sind miteinander verbunden, da sie in derselben Armee dienen. Man könnte sagen, dass die oben aufgeführten Kategorien eine Familie miteinander verbundener Objekte sind. Wir verstehen das. Aber das abstrakte Fabrikmuster wird verwendet, um die Erstellung verschiedener Familien miteinander verbundener Objekte zu organisieren. Auch hier gibt es nichts Kompliziertes. Fahren wir mit dem Beispiel der Militärstrategie fort. Im Allgemeinen gehören Militäreinheiten mehreren verschiedenen Kriegsparteien an. Je nachdem, auf welcher Seite sie stehen, können Militäreinheiten in ihrem Erscheinungsbild erheblich variieren. Die Fußsoldaten, Reiter und Bogenschützen der römischen Armee sind nicht dasselbe wie die Fußsoldaten, Reiter und Bogenschützen der Wikinger. In der Militärstrategie sind Soldaten verschiedener Armeen unterschiedliche Familien miteinander verbundener Objekte. Es wäre lustig, wenn ein Programmierer Dieser Fehler führte dazu, dass ein Soldat in einer französischen Uniform aus der Napoleon-Ära mit schussbereiter Muskete zwischen den Reihen der römischen Infanterie herumlief. Genau zur Lösung dieses Problems wird das abstrakte Fabrikentwurfsmuster benötigt. Nein, nicht das Problem der Peinlichkeit, die eine Zeitreise mit sich bringen kann, sondern das Problem der Schaffung verschiedener Gruppen miteinander verbundener Objekte. Eine abstrakte Fabrik bietet eine Schnittstelle zum Erstellen aller verfügbaren Produkte (einer Objektfamilie). Eine abstrakte Fabrik verfügt normalerweise über mehrere Implementierungen. Jeder von ihnen ist für die Herstellung von Produkten einer der Familien verantwortlich. Unsere militärische Strategie würde eine abstrakte Fabrik umfassen, die abstrakte Fußsoldaten, Bogenschützen und Kavalleristen sowie Implementierungen dieser Fabrik herstellt. Zum Beispiel, eine Fabrik, die römische Legionäre herstellt, und eine Fabrik, die karthagische Soldaten herstellt. Abstraktion ist das wichtigste Leitprinzip dieses Musters. Die Kunden der Fabrik arbeiten ausschließlich über abstrakte Schnittstellen mit der Fabrik und ihren Produkten. Dadurch müssen Sie nicht darüber nachdenken, welche Soldaten gerade erstellt werden. Stattdessen übertragen Sie diese Verantwortung auf eine konkrete Implementierung der abstrakten Fabrik.

Lassen Sie uns unser Café weiter automatisieren

In der letzten Lektion, wir haben das Factory-Methodenmuster untersucht. Wir haben es genutzt, um unser Kaffeegeschäft auszubauen und mehrere neue Standorte zu eröffnen. Heute werden wir unser Unternehmen weiter modernisieren. Mithilfe des abstrakten Fabrikmusters legen wir den Grundstein für eine neue Desktop-Anwendung zur Online-Kaffeebestellung. Beim Schreiben einer Desktop-Anwendung sollten wir immer an die plattformübergreifende Unterstützung denken. Unsere Anwendung muss sowohl auf macOS als auch auf Windows funktionieren (Spoiler: Die Implementierung der Linux-Unterstützung bleibt Ihnen als Hausaufgabe überlassen). Wie wird unsere Bewerbung aussehen? Ganz einfach: Es wird ein Formular sein, das aus einem Textfeld, einem Auswahlfeld und einer Schaltfläche besteht. Wenn Sie Erfahrung mit verschiedenen Betriebssystemen haben, ist Ihnen sicherlich aufgefallen, dass Schaltflächen unter Windows anders dargestellt werden als auf einem Mac. Wie alles andere auch... Nun, fangen wir an.
  • Tasten
  • Textfelder
  • Auswahlfelder
Haftungsausschluss: In jeder Schnittstelle könnten wir Methoden wie onClick, onValueChangedoder definieren onInputChanged. Mit anderen Worten: Wir könnten Methoden definieren, die es uns ermöglichen, verschiedene Ereignisse zu verarbeiten (Knopfdruck, Texteingabe, Auswahl eines Werts in einem Auswahlfeld). All dies wird hier bewusst weggelassen, um das Beispiel nicht zu überladen und es beim Studium des Fabrikmusters klarer 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 des Betriebssystems erstellen. Wir schreiben Code 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 machen wir dasselbe für MacOS:
public class MacButton implements Button {
}

public class MacSelect implements Select {
}

public class MacTextField implements TextField {
}
Exzellent. Jetzt können wir mit unserer abstrakten Fabrik fortfahren, die alle verfügbaren abstrakten Produkttypen erstellt:
public interface GUIFactory {

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

}
Hervorragend. Wie Sie sehen, haben wir noch nichts Kompliziertes gemacht. Auch alles, was folgt, ist einfach. Analog zu den Produkten erstellen wir für jedes Betriebssystem verschiedene Factory-Implementierungen. Beginnen wir mit 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();
    }
}
Wir haben einige Konsolenausgaben innerhalb der Methoden und des Konstruktors hinzugefügt, um das Geschehen weiter zu veranschaulichen. Jetzt für 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();
    }
}
Beachten Sie, dass jede Methodensignatur angibt, dass die Methode einen abstrakten Typ zurückgibt. Aber innerhalb der Methoden erstellen wir spezifische Implementierungen der Produkte. Dies ist der einzige Ort, an dem wir die Erstellung bestimmter Instanzen kontrollieren. Jetzt ist es an der Zeit, eine Klasse für das Formular zu schreiben. Dies ist eine Java-Klasse, deren Felder Schnittstellenelemente sind:
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();
    }
}
Eine abstrakte Fabrik, die Schnittstellenelemente erstellt, wird an den Konstruktor des Formulars übergeben. Wir übergeben die notwendige Factory-Implementierung an den Konstruktor, um Schnittstellenelemente für ein bestimmtes Betriebssystem zu erstellen.
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();
    }
}
Wenn wir die Anwendung unter Windows ausführen, erhalten wir die folgende Ausgabe:
Creating GUIFactory for Windows OS
Creating coffee order 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 GUIFactory for macOS
Creating coffee order form
Creating TextField for macOS
Creating Select for macOS
Creating Button for macOS
Unter Linux:
Unknown OS. Unable to draw form :(
Und jetzt fassen wir zusammen. Wir haben das Grundgerüst einer GUI-basierten Anwendung geschrieben, in der die Schnittstellenelemente speziell für das jeweilige Betriebssystem erstellt werden. Wir wiederholen kurz und bündig, was wir erstellt haben:
  • Eine Produktfamilie bestehend aus einem Eingabefeld, einem Auswahlfeld und einer Schaltfläche.
  • Verschiedene Implementierungen der Produktfamilie für Windows und macOS.
  • Eine abstrakte Fabrik, die eine Schnittstelle zur Erstellung unserer Produkte definiert.
  • Zwei Implementierungen unserer Fabrik, die jeweils für die Herstellung einer bestimmten Produktfamilie verantwortlich sind.
  • Ein Formular (eine Java-Klasse), dessen Felder abstrakte Schnittstellenelemente sind, die im Konstruktor mithilfe einer abstrakten Factory mit den erforderlichen Werten initialisiert werden.
  • Anwendungsklasse Innerhalb dieser Klasse erstellen wir ein Formular und übergeben die gewünschte Factory-Implementierung an seinen Konstruktor.
Das Ergebnis ist, dass wir das abstrakte Fabrikmuster implementiert haben.

Abstrakte Fabrik: Verwendung

Eine abstrakte Fabrik ist ein Entwurfsmuster zur Verwaltung der Erstellung verschiedener Produktfamilien, ohne an konkrete Produktklassen gebunden zu sein. Wenn Sie dieses Muster verwenden, müssen Sie:
  1. Produktfamilien definieren. Angenommen, 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 haben wir:
    • ProductA
    • ProductB
  3. Innerhalb jeder Produktfamilie muss jedes Produkt die in Schritt 2 definierte Schnittstelle implementieren.
  4. Erstellen Sie eine abstrakte Fabrik mit Methoden zum Erstellen jedes in Schritt 2 definierten Produkts. In unserem Fall sind diese Methoden:
    • ProductA createProductA();
    • ProductB createProductB();
  5. Erstellen Sie abstrakte Factory-Implementierungen, sodass jede Implementierung die Erstellung von Produkten einer einzelnen Familie steuert. Dazu müssen Sie in jeder Implementierung der abstrakten Fabrik alle Erstellungsmethoden implementieren, damit sie bestimmte Produktimplementierungen erstellen und zurückgeben.
Das folgende UML-Diagramm veranschaulicht die oben beschriebene Anleitung: Designmuster: Abstrakte Fabrik – 3Jetzt schreiben wir Code gemäß dieser Anleitung:
// 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();
    }
}

Hausaufgaben

Um das Material zu verstärken, können Sie zwei Dinge tun:
  1. Verfeinern Sie die Kaffee-Bestellanwendung so, dass sie auch unter Linux funktioniert.
  2. Erstellen Sie Ihre eigene abstrakte Fabrik zur Herstellung von Einheiten, die an jeder militärischen Strategie beteiligt sind. Dies kann entweder eine historische Militärstrategie mit echten Armeen oder eine Fantasy-Strategie mit Orks, Gnomen und Elfen sein. Wichtig ist, dass Sie etwas auswählen, das Sie interessiert. Seien Sie kreativ, drucken Sie Nachrichten auf der Konsole und lernen Sie gerne etwas über Muster!
Kommentare
  • Beliebt
  • Neu
  • Alt
Du musst angemeldet sein, um einen Kommentar schreiben zu können
Auf dieser Seite gibt es noch keine Kommentare