JavaRush /Java-Blog /Random-DE /Fabrikmethode und abstrakte Fabrikmuster

Fabrikmethode und abstrakte Fabrikmuster

Veröffentlicht in der Gruppe Random-DE
Im Buch „Kopf voran. „Design Patterns“ definiert diese Muster wie folgt: Das Factory-Methodenmuster definiert die Schnittstelle zum Erstellen eines Objekts, ermöglicht jedoch Unterklassen, die Klasse der zu erstellenden Instanz auszuwählen. Somit delegiert die Factory-Methode den Instanziierungsvorgang an Unterklassen. Das Abstract Factory-Muster bietet eine Schnittstelle zum Erstellen von Familien miteinander verbundener oder voneinander abhängiger Objekte, ohne deren konkrete Klassen anzugeben. Versuchen wir, dies genauer zu verstehen. Nehmen wir an, Sie beschließen, ein Spiel über Menschen zu schreiben, die sich dazu entschließen, ... (hier brauchen Sie etwas Originelles und Ungewöhnliches) Mönche zu werden. Wir könnten mit Folgendem beginnen. 1) Erstellen Sie eine Monk-Klasse und untergeordnete Klassen (erstellen wir zuerst eine):
public abstract class Monk {

    public abstract void description();
}
public class OrthodoxMonk extends Monk {
    @Override
    public void description() {
        System.out.println("Я православный монах");
    }
}
2) Und natürlich erstellen Sie einen Klosterkurs, in dem Sie „Klöstergelübde“ umsetzen können:
public class Monastery {
    private Monk monk;

    public void createMonk(String typeName) {
        this.monk = switch (typeName) {
            case "ORTODOX" -> new OrthodoxMonk();
            default -> null;
        };
    }

    public Monk getMonk() {
        return monk;
    }
}
Nun, schauen wir uns das Ergebnis an:
public class Main {
    public static void main(String[] args) {
        Monastery monastery = new Monastery();
        monastery.createMonk("ORTODOX");
        monastery.getMonk().description();
    }
}
Я православный монах
Wenn Sie nun einen katholischen Mönch erstellen müssen, müssen Sie A) eine neue Klasse für einen katholischen Mönch erstellen:
public class CatholicMonk extends Monk {
    @Override
    public void description() {
        System.out.println("Я католический монах");
    }
}
B) Nehmen Sie Änderungen an der Klosterklasse vor:
public class Monastery {
    private Monk monk;

    public void createMonk(String typeName) {
        this.monk = switch (typeName) {
            case "ORTODOX" -> new OrthodoxMonk();
            case "CATHOLIC" -> new CatholicMonk();
            default -> null;
        };
    }

    public Monk getMonk() {
        return monk;
    }
}
Daher müssen Sie jedes Mal, wenn neue Arten von Mönchen eingeführt werden, eine neue Klasse erstellen und die bestehende bearbeiten. Was kann in diesem Fall getan werden, um unsere Klosterklasse irgendwie vor Veränderungen zu „kapseln“. Sie können versuchen, das Factory-Methodenmuster zu verwenden. So wird es aussehen
public abstract class Monk {

    public abstract void description();
}
public class OrthodoxMonk extends Monk {
    @Override
    public void description() {
        System.out.println("Я православный монах");
    }
}
public class CatholicMonk extends Monk {
    @Override
    public void description() {
        System.out.println("Я католический монах");
    }
}
public class AnglicanMonk extends Monk {
    @Override
    public void description() {
        System.out.println("Я англиканский монах");
    }
}
B) Ändern wir die Klosterklasse wie folgt (abstrahieren wir sie und ihre Methode). Hier verwenden wir einfach die Factory-Methode:
public abstract class Monastery {
    protected abstract Monk createMonk();
}
und untergeordnete Klassen mit Methodenimplementierung erstellen:
public class OrthodoxMonastery extends Monastery {
    @Override
    protected Monk createMonk() {
        return new OrthodoxMonk();
    }
}
public class CatholicMonastery extends Monastery {
    @Override
    protected Monk createMonk() {
        return new CatholicMonk();
    }
}
public class AnglicanMonastery extends Monastery {
    @Override
    protected Monk createMonk() {
        return new AnglicanMonk();
    }
}
B) Lassen Sie uns den Code überprüfen
public class Main {
    public static void main(String[] args) {
        Monastery monastery;

        monastery = new OrthodoxMonastery();
        monastery.createMonk().description();

        monastery = new CatholicMonastery();
        monastery.createMonk().description();

        monastery = new AnglicanMonastery();
        monastery.createMonk().description();
    }
}
Я православный монах
Я католический монах
Я англиканский монах
Diese. Wie wir jetzt sehen, besteht beim Hinzufügen neuer Mönchstypen keine Notwendigkeit, bestehende Klassen zu ändern, sondern nur bei Bedarf neue hinzuzufügen (die Klasse eines bestimmten Klosters und Mönchs). Vielleicht ist jemandem schon aufgefallen, dass die Beschreibungsmethode, die es von Anfang an in der Monk-Klasse gab, auch Factory war :) Die Definition der Factory-Methode besagte, dass unser Muster die Schnittstelle zum Erstellen eines Objekts definiert, aber wir haben keine erstellt Schnittstellen, obwohl wir die Monastery-Klasse als Schnittstelle erstellen und in bestimmten Implementierungen implementieren könnten. Damit ist das Wort „Schnittstelle“ im weiteren Sinne gemeint. Die Definition besagte auch, dass Unterklassen die Klasse der von ihnen erstellten Instanz auswählen können . Hier sehen wir nur, dass Unterklassen (untergeordnete Klassen) diese Methode implementieren (d. h. diese Befugnisse zum Erstellen von Monk-Objekten werden an sie delegiert). Lassen Sie uns nun unser Programm ein wenig erweitern und die Möglichkeit einführen, dass es in der einen oder anderen Konfession unterschiedliche Mönche gibt. Beispielsweise können wir in der Orthodoxie aufgrund der Position der orthodoxen Kirche zu Klöstern und Mönchen (verabschiedet vom Bischofsrat der Russisch-Orthodoxen Kirche vom 29. November bis 2. Dezember 2017) den Schluss ziehen, dass es zwei Arten von Mönchen gibt : - Kleineres Schema (Mantel). - Schema (großartiges Schema). Es gibt auch „Vorbereitungsphasen“, aber Menschen gelten nicht als Mönche (Trudnik, Novize und Ryasophor oder Mönch), da sie keine Mönchsgelübde ablegen. Daher berücksichtigen wir sie nicht. Was erhalten wir in diesem Fall: A) Klosterklasse (zur Vereinfachung konzentrieren wir uns zunächst auf das orthodoxe Mönchtum) mit der Factory-Methode :
public abstract class Monastery {
    protected abstract Monk createMonk(String type);
}
und ein bestimmtes Kloster
public class OrthodoxMonastery extends Monastery {

    @Override
    protected Monk createMonk(String type) {
        return new OrthodoxMonk(type);
    }
}
B) Lassen Sie uns die Mönchsklasse reparieren:
public abstract class Monk {
    String kind;

    public Monk(String kind) {
        this.kind = kind;
    }

    public abstract void description();
}
und Kinderklasse:
public class OrthodoxMonk extends Monk {
    public OrthodoxMonk(String kind) {
        super(kind);
    }

    @Override
    public void description() {
        System.out.println("Я православный монах - " + kind);
    }
}
C) Schauen wir uns unseren Code an:
public class Main {
    public static void main(String[] args) {
        Monastery monastery = new OrthodoxMonastery();
        monastery.createMonk("Мантийный монах").description();
        monastery.createMonk("Великосхимник").description();
    }
}
Я православный монах - Мантийный монах
Я православный монах — Великосхимник
Durch die Verwendung des Factory-Methode-Musters haben wir somit erreicht, dass wir zuvor geschriebene Klassen nicht ändern müssen, aber auch beim Erweitern der Bilder (Typen) von Mönchen sind nur minimale Änderungen im Code erforderlich. Schauen wir uns alle Orden und Kongregationen katholischer Mönche an und fügen sie hinzu :) Aber es ist besser, sich auf die drei berühmtesten zu konzentrieren, denn es gibt mehr als 100 davon: 1) Benediktiner, 2) Jesuiten, 3) Franziskaner. Dies geschieht wie zuvor mit Als orthodoxer Mönch müssen wir eine bestimmte Klasse katholischer Mönche umsetzen:
public class CatholicMonk extends Monk {
    public CatholicMonk(String kind) {
        super(kind);
    }

    @Override
    public void description() {
        System.out.println("Я католический монах - " + kind);
    }
}
und Klosterklasse:
public class CatholicMonastery extends Monastery {

    @Override
    protected Monk createMonk(String type) {
        return new CatholicMonk(type);
    }
}
und überprüfen Sie den Code:
public class Main {
    public static void main(String[] args) {
        Monastery monastery;

        monastery = new OrthodoxMonastery();
        monastery.createMonk("Мантийный монах").description();
        monastery.createMonk("Великосхимник").description();

        monastery = new CatholicMonastery();
        monastery.createMonk("Бенедиктинец").description();
        monastery.createMonk("Иезуит").description();
        monastery.createMonk("Францисканец").description();
    }
}
Я православный монах - Мантийный монах
Я православный монах - Великосхимник
Я католический монах - Бенедиктинец
Я католический монах - Иезуит
Я католический монах - Францисканец
Lassen Sie uns mit diesem Muster abschließen. Alle diese Arten von Mönchen könnten auch im Voraus zur E-num-Klasse hinzugefügt werden, aber um den Code zu vereinfachen, verzichten wir darauf. Es ist Zeit für das Abstract Factory-Muster. Wir haben Mönche, jetzt könnten wir ihnen Kleidung, Rosenkränze usw. anfertigen. Beginnen wir mit der Kleidung, das heißt, wenn wir zu unserer Definition vom Anfang zurückkehren, wird Kleidung zu einer Familie miteinander verbundener oder voneinander abhängiger Objekte . Beginnen wir mit dem Problem, dass jeder Mönchstyp unterschiedliche Gewänder hat. Wenn wir auch Buddhisten hinzufügen, werden sie völlig anders sein :) Dazu können wir eine Factory-Schnittstelle erstellen, deren Implementierungen die notwendigen Kleidungsstücke erstellen würden. Deshalb A) Wir gründen eine Fabrik zur Herstellung von Kleidung
public interface MonkFactory {
    Clothing createClothing();
}
und seine Umsetzung
public class OrthodoxMonkFactory implements MonkFactory {

        @Override
    public Clothing createClothing() {
        return new OrtodoxClothing();
    }
}
public class CatholicMonkFactory implements MonkFactory {

    @Override
    public Clothing createClothing() {
        return new CatholicClothing();
    }
}
public class AnglicanMonkFactory implements MonkFactory {

    @Override
    public Clothing createClothing() {
        return new AnglicanClothing();
    }
}
Nun, vergessen wir nicht die buddhistischen Mönche :)
public class BuddhistMonkFactory implements MonkFactory {

    @Override
    public Clothing createClothing() {
        return new BuddhistClothing();
    }
}
B) Erstellen Sie eine Kleidungsklasse (zur Vereinfachung nehmen wir das Schlüsselelement der Mönchskleidung, wir gehen nicht ins Detail):
public abstract class Clothing {
    private String name;

    public Clothing(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}
und Kinderklassen
public class OrtodoxClothing extends Clothing {
    public OrtodoxClothing() {
        super("Мантия");
    }
}
public class CatholicClothing extends Clothing {
    public CatholicClothing() {
        super("Ряса с капюшоном");
    }
}
public class AnglicanClothing extends Clothing {
    public AnglicanClothing() {
        super("Ряса");
    }
}
public class BuddhistClothing extends Clothing {
    public BuddhistClothing() {
        super("Кашая");
    }
}
C) Als nächstes ändern wir die Klasse der Mönche, sodass sie Kleidung haben:
public abstract class Monk {
    String kind;
    Clothing clothing;

    public Monk(String kind) {
        this.kind = kind;
    }

    public void setClothing(Clothing clothing) {
        this.clothing = clothing;
    }

    public abstract void description();
}
public class OrthodoxMonk extends Monk {
    public OrthodoxMonk(String kind) {
        super(kind);
    }

    @Override
    public void description() {
        System.out.println("Я православный монах - " + kind);
        System.out.println("Моя одежда - " + clothing.getName());
    }
}
public class CatholicMonk extends Monk {
    public CatholicMonk(String kind) {
        super(kind);
    }

    @Override
    public void description() {
        System.out.println("Я католический монах - " + kind);
        System.out.println("Моя одежда - " + clothing.getName());
    }
}
public class AnglicanMonk extends Monk {
    public AnglicanMonk(String kind) {
        super(kind);
    }

    @Override
    public void description() {
        System.out.println("Я англиканский монах - " + kind);
        System.out.println("Моя одежда - " + clothing.getName());
    }
}
public class BuddhistMonk extends Monk {
    public BuddhistMonk(String kind) {
        super(kind);
    }

    @Override
    public void description() {
        System.out.println("Я буддийский монах - " + kind);
        System.out.println("Моя одежда - " + clothing.getName());
    }
}
D) Die Monastery-Klasse enthält unsere Factory-Methode
public abstract class Monastery {

    public Monk create(MonkFactory monkFactory, String type) {
        Monk monk = createMonk(type);
        monk.setClothing(monkFactory.createClothing());
        return monk;
    }

    protected abstract Monk createMonk(String type);
}
Unsere Implementierungen haben sich nicht geändert
public class OrthodoxMonastery extends Monastery {

    @Override
    protected Monk createMonk(String type) {
        return new OrthodoxMonk(type);
    }
}
public class CatholicMonastery extends Monastery {

    @Override
    protected Monk createMonk(String type) {
        return new CatholicMonk(type);
    }
}
public class AnglicanMonastery extends Monastery {

    @Override
    protected Monk createMonk(String type) {
        return new AnglicanMonk(type);
    }
}
public class BuddhistMonastery extends Monastery {

    @Override
    protected Monk createMonk(String type) {
        return new BuddhistMonk(type);
    }
}
D) Überprüfen Sie das Ergebnis:
public class Main {
    public static void main(String[] args) {
        Monastery monastery;

        monastery = new OrthodoxMonastery();
        monastery.create(new OrthodoxMonkFactory(), "Мантийный монах").description();

        monastery = new CatholicMonastery();
        monastery.create(new CatholicMonkFactory(), "Иезуит").description();

        monastery = new AnglicanMonastery();
        monastery.create(new AnglicanMonkFactory(), "Бенедиктинец").description();

        monastery = new BuddhistMonastery();
        monastery.create(new BuddhistMonkFactory(), "Монах").description();
    }
}
Я православный монах - Мантийный монах
Моя одежда - Мантия
Я католический монах - Иезуит
Моя одежда - Ряса с капюшоном
Я англиканский монах - Бенедиктинец
Моя одежда - Ряса
Я буддийский монах - Монах
Моя одежда - Кашая
Die Fabrik, die Kleidung herstellt, hat ihren Betrieb gut aufgenommen. Jetzt können Sie die Fabrik um die Produktion von Ausrüstung für Mönche für ein erfolgreiches Gebet (Rosenkränze usw.) erweitern. Aber es bleibt immer noch die Frage: Ist es möglich, zwei Muster zusammen zu verwenden? Natürlich können Sie das :) Versuchen wir, die endgültige Version unseres Projekts zu erstellen und einen Hindu-Mönch hinzuzufügen: A) Fabriken erschaffen jetzt Mönche, das klingt wie eine „Sternenfabrik“ :
public interface MonkFactory {
    Monk createMonk(String type);
    Clothing createClothing();
}
public class OrthodoxMonkFactory implements MonkFactory {

    @Override
    public Monk createMonk(String type){
        return new OrthodoxMonk(type);
    }

    @Override
    public Clothing createClothing() {
        return new OrtodoxClothing();
    }
}
public class CatholicMonkFactory implements MonkFactory {

    @Override
    public Monk createMonk(String type){
        return new CatholicMonk(type);
    }

    @Override
    public Clothing createClothing() {
        return new CatholicClothing();
    }
}
public class AnglicanMonkFactory implements MonkFactory {

    @Override
    public Monk createMonk(String type){
        return new AnglicanMonk(type);
    }

    @Override
    public Clothing createClothing() {
        return new AnglicanClothing();
    }
}
public class BuddhistMonkFactory implements MonkFactory {

    @Override
    public Monk createMonk(String type){
        return new BuddhistMonk(type);
    }

    @Override
    public Clothing createClothing() {
        return new BuddhistClothing();
    }
}
public class HinduMonkFactory implements MonkFactory {

    @Override
    public Monk createMonk(String type){
        return new HinduMonk(type);
    }

    @Override
    public Clothing createClothing() {
        return new HinduClothing();
    }
}
B) Die Klosterklasse + konkrete Implementierungen der Klosterklasse werden nicht benötigt, sie werden von der Fabrik implementiert (im Gegenteil, wir könnten sie belassen und die Fabriken entfernen, aber im Wesentlichen wären sie dann einfach anstelle von Fabriken, nur in In diesem Fall müsste das Kloster dann zu einer Schnittstelle und nicht zu einer abstrakten Klasse gemacht werden. Und fügen Sie die Anwendungsklasse hinzu:
public class Application {

    public Monk create(MonkFactory monkFactory, String type) {
        Monk monk = monkFactory.createMonk(type);
        monk.prepare(monkFactory);
        return monk;
    }
}
B) Mönche enthalten jetzt
public abstract class Monk {
    String kind;
    Clothing clothing;

    public Monk(String kind) {
        this.kind = kind;
    }

    public void setClothing(Clothing clothing) {
        this.clothing = clothing;
    }

    public abstract void description();

    public abstract void prepare(MonkFactory monkFactory);
}
enthält eine Factory-Methode in Implementierungen, die mithilfe einer Factory implementiert wird:
public class OrthodoxMonk extends Monk {

    public OrthodoxMonk(String kind) {
        super(kind);
    }

    @Override
    public void description() {
        System.out.println("Я православный монах - " + kind);
        System.out.println("Моя одежда - " + clothing.getName());
    }

    @Override
    public void prepare(MonkFactory monkFactory) {
        setClothing(monkFactory.createClothing());
    }
}
public class CatholicMonk extends Monk {
    public CatholicMonk(String kind) {
        super(kind);
    }

    @Override
    public void description() {
        System.out.println("Я католический монах - " + kind);
        System.out.println("Моя одежда - " + clothing.getName());
    }

    @Override
    public void prepare(MonkFactory monkFactory) {
        setClothing(monkFactory.createClothing());
    }
}
public class AnglicanMonk extends Monk {
    public AnglicanMonk(String kind) {
        super(kind);
    }

    @Override
    public void description() {
        System.out.println("Я англиканский монах - " + kind);
        System.out.println("Моя одежда - " + clothing.getName());
    }

    @Override
    public void prepare(MonkFactory monkFactory) {
        setClothing(monkFactory.createClothing());
    }
}
public class BuddhistMonk extends Monk {
    public BuddhistMonk(String kind) {
        super(kind);
    }

    @Override
    public void description() {
        System.out.println("Я буддийский монах - " + kind);
        System.out.println("Моя одежда - " + clothing.getName());
    }

    @Override
    public void prepare(MonkFactory monkFactory) {
        setClothing(monkFactory.createClothing());
    }
}
public class HinduMonk extends Monk {
    public HinduMonk(String kind) {
        super(kind);
    }

    @Override
    public void description() {
        System.out.println("Я индуистский монах - " + kind);
        System.out.println("Моя одежда - " + clothing.getName());
    }

    @Override
    public void prepare(MonkFactory monkFactory) {
        setClothing(monkFactory.createClothing());
    }
}
D) Und schauen wir uns an:
public class Main {
    public static void main(String[] args) {
        Application application = new Application();

        application.create(new OrthodoxMonkFactory(), "Мантийный монах").description();
        application.create(new CatholicMonkFactory(), "Иезуит").description();
        application.create(new AnglicanMonkFactory(), "Бенедиктинец").description();
        application.create(new BuddhistMonkFactory(), "Монах").description();
        application.create(new HinduMonkFactory(), "Саньяси").description();
    }
}
Я православный монах - Мантийный монах
Моя одежда - Мантия
Я католический монах - Иезуит
Моя одежда - Ряса с капюшоном
Я англиканский монах - Бенедиктинец
Моя одежда - Ряса
Я буддийский монах - Монах
Моя одежда - Кашая
Я индуистский монах - Саньяси
Моя одежда - Почти ничего, тепло же :)
Zusammenfassend lässt sich festhalten, dass die Factory-Methode eine abstrakte Klasse mit einer nicht implementierten Methode verwendete, die in Unterklassen implementiert wurde, und dass die Abstract Factory eine Schnittstelle verwendete, bei der die Implementierung (in unserem Fall die Erstellung eines Monks) in implementierten Klassen erfolgte diese Schnittstelle.
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION