JavaRush /Java-Blog /Random-DE /Entwurfsmuster: FactoryMethod

Entwurfsmuster: FactoryMethod

Veröffentlicht in der Gruppe Random-DE
Hallo! Heute werden wir weiterhin Entwurfsmuster untersuchen und über die Fabrikmethode (FactoryMethod) sprechen. Entwurfsmuster: FactoryMethod – 1Sie erfahren, was es ist und für welche Aufgaben diese Vorlage geeignet ist. Wir werden uns dieses Entwurfsmuster in der Praxis ansehen und seine Struktur untersuchen. Um Ihnen all das zu verdeutlichen, müssen Sie die folgenden Themen verstehen:
  1. Vererbung in Java.
  2. Abstrakte Methoden und Klassen in Java.

Welches Problem löst die Factory-Methode?

Bei allen Fabrikdesignmustern gibt es zwei Teilnehmergruppen: Schöpfer (die Fabriken selbst) und Produkte (die von den Fabriken geschaffenen Objekte). Stellen Sie sich die Situation vor: Wir haben eine Fabrik, die Autos unter der Marke AutoRush produziert. Sie weiß, wie man Automodelle mit verschiedenen Karosserietypen erstellt:
  • Limousinen
  • Kombis
  • Coupe
Für uns lief es so gut, dass wir eines schönen Tages den OneAuto-Konzern übernommen haben. Als vernünftige Manager wollen wir keine OneAuto-Kunden verlieren und unsere Aufgabe ist es, die Produktion so umzustrukturieren, dass wir produzieren können:
  • AutoRush-Limousinen
  • AutoRush-Kombis
  • Coupé AutoRush
  • OneAuto-Limousinen
  • OneAuto Kombis
  • Coupé OneAuto
Wie Sie sehen, sind statt einer Gruppe von Derivatprodukten zwei entstanden, die sich in einigen Details unterscheiden. Das Entwurfsmuster der Fabrikmethode löst das Problem der Erstellung verschiedener Produktgruppen mit jeweils bestimmten Besonderheiten. Wir werden das Prinzip dieser Vorlage in der Praxis betrachten und dabei schrittweise vom Einfachen zum Komplexen übergehen, am Beispiel unseres Cafés, das wir in einer der vorherigen Vorlesungen erstellt haben .

Ein wenig über die Fabrikvorlage

Ich möchte Sie daran erinnern: Wir haben mit Ihnen ein kleines virtuelles Café aufgebaut. Darin haben wir gelernt, wie man mit einer einfachen Fabrik verschiedene Kaffeesorten herstellt. Heute werden wir dieses Beispiel verfeinern. Erinnern wir uns daran, wie unser Café mit einer einfachen Fabrik aussah. Wir hatten einen Kaffeekurs:
public class Coffee {
    public void grindCoffee(){
        // перемалываем кофе
    }
    public void makeCoffee(){
        // делаем кофе
    }
    public void pourIntoCup(){
        // наливаем в чашку
    }
}
Und auch einige seiner Erben – spezifische Kaffeesorten, die unsere Fabrik produzieren könnte:
public class Americano extends Coffee {}
public class Cappuccino extends Coffee {}
public class CaffeLatte extends Coffee {}
public class Espresso extends Coffee {}
Um die Annahme von Bestellungen zu vereinfachen, haben wir Überweisungen eingeführt:
public enum CoffeeType {
    ESPRESSO,
    AMERICANO,
    CAFFE_LATTE,
    CAPPUCCINO
}
Die Kaffeefabrik selbst sah so aus:
public class SimpleCoffeeFactory {
    public Coffee createCoffee (CoffeeType type) {
        Coffee coffee = null;

        switch (type) {
            case AMERICANO:
                coffee = new Americano();
                break;
            case ESPRESSO:
                coffee = new Espresso();
                break;
            case CAPPUCCINO:
                coffee = new Cappuccino();
                break;
            case CAFFE_LATTE:
                coffee = new CaffeLatte();
                break;
        }

        return coffee;
    }
}
Und schließlich das Café selbst:
public class CoffeeShop {

    private final SimpleCoffeeFactory coffeeFactory;

    public CoffeeShop(SimpleCoffeeFactory coffeeFactory) {
        this.coffeeFactory = coffeeFactory;
    }

    public Coffee orderCoffee(CoffeeType type) {
        Coffee coffee = coffeeFactory.createCoffee(type);
        coffee.grindCoffee();
        coffee.makeCoffee();
        coffee.pourIntoCup();

        System.out.println("Вот ваш кофе! Спасибо, приходите еще!");
        return coffee;
    }
}

Modernisierung einer einfachen Fabrik

Unserem Café geht es gut. So sehr, dass wir über eine Erweiterung nachdenken. Wir möchten mehrere neue Punkte eröffnen. Als unternehmungslustige Leute werden wir keine eintönigen Coffeeshops eröffnen. Ich möchte, dass jeder seine eigene Wendung hat. Daher eröffnen wir zunächst zwei Punkte: im italienischen und im amerikanischen Stil. Die Änderungen betreffen nicht nur das Interieur, sondern auch die Getränke:
  • In einem italienischen Café verwenden wir ausschließlich italienische Kaffeemarken mit spezieller Mahlung und Röstung.
  • Die amerikanische Portion wird etwas größer sein und zu jeder Bestellung servieren wir geschmolzene Marshmallows – Marshmallows.
Das Einzige, was unverändert bleibt, ist unser Geschäftsmodell, das sich bewährt hat. Wenn wir in Codesprache sprechen, passiert Folgendes. Wir hatten 4 Produktklassen:
public class Americano extends Coffee {}
public class Cappuccino extends Coffee {}
public class CaffeLatte extends Coffee {}
public class Espresso extends Coffee {}
Und es wird 8:
public class ItalianStyleAmericano extends Coffee {}
public class ItalianStyleCappucino extends Coffee {}
public class ItalianStyleCaffeLatte extends Coffee {}
public class ItalianStyleEspresso extends Coffee {}

public class AmericanStyleAmericano extends Coffee {}
public class AmericanStyleCappucino extends Coffee {}
public class AmericanStyleCaffeLatte extends Coffee {}
public class AmericanStyleEspresso extends Coffee {}
Da wir das aktuelle Geschäftsmodell unverändert beibehalten möchten, möchten wir, dass die Methode orderCoffee(CoffeeType type)möglichst wenig Änderungen erfährt. Werfen wir einen Blick darauf:
public Coffee orderCoffee(CoffeeType type) {
    Coffee coffee = coffeeFactory.createCoffee(type);
    coffee.grindCoffee();
    coffee.makeCoffee();
    coffee.pourIntoCup();

    System.out.println("Вот ваш кофе! Спасибо, приходите еще!");
    return coffee;
}
Welche Möglichkeiten haben wir? Wir wissen doch schon, wie man eine Fabrik schreibt, oder? Das einfachste, was mir sofort in den Sinn kommt, ist, zwei ähnliche Fabriken zu schreiben und dann die erforderliche Implementierung im Konstruktor an unser Café zu übergeben. Dann wird sich die Klasse des Coffeeshops nicht ändern. Zuerst müssen wir eine neue Factory-Klasse erstellen, von unserer einfachen Factory erben und diese überschreiben createCoffee (CoffeeType type). Schreiben wir Fabriken für die Zubereitung von Kaffee im italienischen und amerikanischen Stil:
public class SimpleItalianCoffeeFactory extends SimpleCoffeeFactory {

    @Override
    public Coffee createCoffee (CoffeeType type) {
        Coffee coffee = null;
        switch (type) {
            case AMERICANO:
                coffee = new ItalianStyleAmericano();
                break;
            case ESPRESSO:
                coffee = new ItalianStyleEspresso();
                break;
            case CAPPUCCINO:
                coffee = new ItalianStyleCappuccino();
                break;
            case CAFFE_LATTE:
                coffee = new ItalianStyleCaffeLatte();
                break;
        }
        return coffee;
    }
}

public class SimpleAmericanCoffeeFactory extends SimpleCoffeeFactory{

    @Override
    public Coffee createCoffee (CoffeeType type) {
        Coffee coffee = null;

        switch (type) {
            case AMERICANO:
                coffee = new AmericanStyleAmericano();
                break;
            case ESPRESSO:
                coffee = new AmericanStyleEspresso();
                break;
            case CAPPUCCINO:
                coffee = new AmericanStyleCappuccino();
                break;
            case CAFFE_LATTE:
                coffee = new AmericanStyleCaffeLatte();
                break;
        }

        return coffee;
    }

}
Jetzt können wir die erforderliche Factory-Implementierung an CoffeeShop übergeben. Sehen wir uns an, wie der Code zum Bestellen von Kaffee in verschiedenen Coffeeshops aussehen würde. Zum Beispiel Cappuccino im italienischen und amerikanischen Stil:
public class Main {
    public static void main(String[] args) {
        /*
            Закажем капучино в итальянском стиле:
            1. Создадим фабрику для приготовления итальянского кофе
            2. Создадим новую кофейню, передав ей в конструкторе фабрику итальянского кофе
            3. Закажем наш кофе
         */
        SimpleItalianCoffeeFactory italianCoffeeFactory = new SimpleItalianCoffeeFactory();
        CoffeeShop italianCoffeeShop = new CoffeeShop(italianCoffeeFactory);
        italianCoffeeShop.orderCoffee(CoffeeType.CAPPUCCINO);


         /*
            Закажем капучино в американском стиле
            1. Создадим фабрику для приготовления американского кофе
            2. Создадим новую кофейню, передав ей в конструкторе фабрику американского кофе
            3. Закажем наш кофе
         */
        SimpleAmericanCoffeeFactory americanCoffeeFactory = new SimpleAmericanCoffeeFactory();
        CoffeeShop americanCoffeeShop = new CoffeeShop(americanCoffeeFactory);
        americanCoffeeShop.orderCoffee(CoffeeType.CAPPUCCINO);
    }
}
Wir haben zwei verschiedene Coffeeshops eingerichtet und jeweils in die gewünschte Fabrik verlegt. Einerseits haben wir unser Ziel erreicht, aber andererseits... Irgendetwas kratzt an der unbändigen Seele des Unternehmers... Lassen Sie uns herausfinden, was los ist. Erstens die Fülle an Fabriken. Ist es möglich, jedes Mal eine eigene Fabrik für einen neuen Punkt zu erstellen und zusätzlich darauf zu achten, dass beim Erstellen eines Cafés die erforderliche Fabrik an den Konstrukteur übergeben wird? Zweitens ist es immer noch eine einfache Fabrik. Nur ein wenig modernisiert. Wir studieren hier immer noch ein neues Muster. Drittens: Ist es nicht möglich, es anders zu machen? Es wäre cool, wenn wir alle Fragen zur Kaffeezubereitung innerhalb des Klassenzimmers lokalisieren könnten CoffeeShop, indem wir die Prozesse der Kaffeezubereitung und der Auftragsabwicklung verknüpfen und gleichzeitig genügend Flexibilität bewahren könnten, um Kaffee in verschiedenen Stilrichtungen zuzubereiten. Die Antwort lautet: Ja, das können Sie. Dies wird als Factory-Methodenentwurfsmuster bezeichnet.

Von einer einfachen Fabrik zu einer Fabrikmethode

Um das Problem so effizient wie möglich zu lösen, tun wir:
  1. createCoffee(CoffeeType type)Lassen Sie uns die Methode an die Klasse zurückgeben CoffeeShop.
  2. Machen wir diese Methode abstrakt.
  3. Die Klasse selbst CoffeeShopwird abstrakt.
  4. Die Klasse CoffeeShopwird Erben haben.
Ja Freund. Ein italienisches Café ist nichts anderes als ein Erbe der Klasse CoffeeShop, das eine Methode anwendet createCoffee(CoffeeType type), die den besten Traditionen italienischer Baristas entspricht. Also der Reihe nach. Schritt 1. Lassen Sie uns die Klasse Coffeeabstrakt machen. Wir haben jetzt zwei Familien unterschiedlicher Produkte. Italienische und amerikanische Kaffeegetränke haben immer noch einen gemeinsamen Vorfahren: den Coffee. Es wäre richtig, es abstrakt zu machen:
public abstract class Coffee {
    public void makeCoffee(){
        // делаем кофе
    }
    public void pourIntoCup(){
        // наливаем в чашку
    }
}
Schritt 2. Machen Sie es CoffeeShopabstrakt, mit einer abstrakten MethodecreateCoffee(CoffeeType type)
public abstract class CoffeeShop {

    public Coffee orderCoffee(CoffeeType type) {
        Coffee coffee = createCoffee(type);

        coffee.makeCoffee();
        coffee.pourIntoCup();

        System.out.println("Вот ваш кофе! Спасибо, приходите еще!");
        return coffee;
    }

    protected abstract Coffee createCoffee(CoffeeType type);
}
Schritt 3. Erstellen Sie ein italienisches Café, eine Nachfolgeklasse des abstrakten Cafés. Darin implementieren wir die Methode createCoffee(CoffeeType type)unter Berücksichtigung italienischer Besonderheiten.
public class ItalianCoffeeShop extends CoffeeShop {

    @Override
    public Coffee createCoffee (CoffeeType type) {
        Coffee coffee = null;
        switch (type) {
            case AMERICANO:
                coffee = new ItalianStyleAmericano();
                break;
            case ESPRESSO:
                coffee = new ItalianStyleEspresso();
                break;
            case CAPPUCCINO:
                coffee = new ItalianStyleCappuccino();
                break;
            case CAFFE_LATTE:
                coffee = new ItalianStyleCaffeLatte();
                break;
        }
        return coffee;
    }
}
Schritt 4. Machen wir dasselbe für ein Café im amerikanischen Stil.
public class AmericanCoffeeShop extends CoffeeShop {
    @Override
    public Coffee createCoffee (CoffeeType type) {
        Coffee coffee = null;

        switch (type) {
            case AMERICANO:
                coffee = new AmericanStyleAmericano();
                break;
            case ESPRESSO:
                coffee = new AmericanStyleEspresso();
                break;
            case CAPPUCCINO:
                coffee = new AmericanStyleCappuccino();
                break;
            case CAFFE_LATTE:
                coffee = new AmericanStyleCaffeLatte();
                break;
        }

        return coffee;
    }
}
Schritt 5. Schauen wir uns an, wie die Bestellung eines Latte Macchiato im amerikanischen und italienischen Stil aussehen würde:
public class Main {
    public static void main(String[] args) {
        CoffeeShop italianCoffeeShop = new ItalianCoffeeShop();
        italianCoffeeShop.orderCoffee(CoffeeType.CAFFE_LATTE);

        CoffeeShop americanCoffeeShop = new AmericanCoffeeShop();
        americanCoffeeShop.orderCoffee(CoffeeType.CAFFE_LATTE);
    }
}
Gratuliere dir. Wir haben gerade das Designmuster der Fabrikmethode in unserem Café implementiert.

So funktioniert die Factory-Methode

Schauen wir uns nun genauer an, was wir haben. Das folgende Diagramm zeigt die resultierenden Klassen. Grüne Blöcke sind Erstellerklassen, blaue Blöcke sind Produktklassen. Entwurfsmuster: FactoryMethod – 2Welche Schlussfolgerungen lassen sich ziehen?
  1. Alle Produkte sind Implementierungen der abstrakten Klasse Coffee.
  2. Alle Ersteller sind Implementierungen der abstrakten Klasse CoffeeShop.
  3. Wir beobachten zwei parallele Klassenhierarchien:
    • Hierarchie der Produkte. Wir sehen italienische Nachkommen und amerikanische Nachkommen
    • Hierarchie der Schöpfer. Wir sehen italienische Nachkommen und amerikanische Nachkommen
  4. Die Oberklasse CoffeeShopverfügt über keine Informationen darüber, welche spezifische Produktimplementierung ( Coffee) erstellt wird.
  5. Eine Oberklasse CoffeeShopdelegiert die Erstellung eines bestimmten Produkts an seine Nachkommen.
  6. Jede Nachkommenklasse CoffeeShopimplementiert eine Factory-Methode createCoffee()gemäß ihren Besonderheiten. Mit anderen Worten: Innerhalb der Implementierungen von Erstellerklassen wird eine Entscheidung getroffen, ein bestimmtes Produkt basierend auf den Besonderheiten der Erstellerklasse vorzubereiten.
Jetzt können Sie das Factory-Methodenmuster definieren . Das Factory-Methodenmuster definiert die Schnittstelle zum Erstellen eines Objekts, ermöglicht es Unterklassen jedoch, die Klasse der zu erstellenden Instanz auszuwählen. Somit delegiert die Factory-Methode den Instanziierungsvorgang an Unterklassen. Im Allgemeinen ist es nicht so wichtig, sich an die Definition zu erinnern, wie zu verstehen, wie die Dinge funktionieren.

Struktur der Factory-Methode

Entwurfsmuster: FactoryMethod – 3Das obige Diagramm zeigt die allgemeine Struktur des Factory-Methodenmusters. Was ist hier noch wichtig?
  1. Die Creator-Klasse enthält Implementierungen aller Methoden, die mit Produkten interagieren, mit Ausnahme der Factory-Methode.
  2. Eine abstrakte Methode factoryMethod()muss von allen Nachkommen der Klasse implementiert werden Creator.
  3. Die Klasse ConcreteCreatorimplementiert eine Methode factoryMethod(), die direkt ein Produkt erzeugt.
  4. Diese Klasse ist für die Erstellung spezifischer Produkte verantwortlich. Dies ist der einzige Kurs mit Informationen zum Erstellen dieser Produkte.
  5. Alle Produkte müssen eine gemeinsame Schnittstelle implementieren – also Nachkommen einer gemeinsamen Produktklasse sein. Dies ist notwendig, damit Klassen, die Produkte verwenden, diese auf der Ebene von Abstraktionen und nicht auf der Ebene konkreter Implementierungen bearbeiten können.

Hausaufgaben

Heute haben wir also ziemlich viel gearbeitet und das Entwurfsmuster der Fabrikmethode studiert. Es ist Zeit, den behandelten Stoff zu festigen! Aufgabe 1. Arbeiten Sie daran, ein weiteres Café zu eröffnen. Es kann im englischen oder spanischen Stil hergestellt werden. Oder sogar im Stil eines Raumschiffs. Fügen wir dem Kaffee Lebensmittelfarbe hinzu, damit er glänzt, und im Allgemeinen wird der Kaffee nur Platz sein! Aufgabe 2. In der letzten Vorlesung hatten Sie die Aufgabe, eine virtuelle Sushi-Bar oder eine virtuelle Pizzeria zu erstellen. Ihre Aufgabe ist es, nicht stillzustehen. Heute haben Sie erfahren, wie Sie mit dem Factory-Methodenmuster erfolgreich sein können. Es ist Zeit, dieses Wissen zu nutzen und Ihr eigenes Geschäft zu erweitern ;)
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION