JavaRush /Java Blog /Random-JA /ファクトリ メソッドと抽象ファクトリ パターン

ファクトリ メソッドと抽象ファクトリ パターン

Random-JA グループに公開済み
著書に『ヘッドファースト。「デザイン パターン」では、これらのパターンを次のように定義しています。 ファクトリ メソッド パターンは、オブジェクトを作成するためのインターフェイスを定義しますが、サブクラスは作成するインスタンスのクラスを選択できます。したがって、Factory メソッドはインスタンス化操作をサブクラスに委任します。Abstract Factory パターンは、具体的なクラスを指定せずに、相互関連または相互依存するオブジェクトのファミリーを作成するためのインターフェイスを提供します。 これをさらに詳しく理解してみましょう。たとえば、僧侶になることを決意した人々についてのゲームを書くことにしたとします (ここでは何か独創的で珍しいものが必要です) 。以下から始めることができます。1) Monk クラスと子クラスを作成します (最初に 1 つ作成しましょう)。
public abstract class Monk {

    public abstract void description();
}
public class OrthodoxMonk extends Monk {
    @Override
    public void description() {
        System.out.println("Я православный монах");
    }
}
2) そしてもちろん、「修道院の誓い」を実行できる修道院クラスを作成します。
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;
    }
}
さて、結果を確認してみましょう:
public class Main {
    public static void main(String[] args) {
        Monastery monastery = new Monastery();
        monastery.createMonk("ORTODOX");
        monastery.getMonk().description();
    }
}
Я православный монах
ここで、カトリック修道士を作成する必要がある場合は、次の手順を実行する必要があります。A) カトリック修道士用の新しいクラスを作成します。
public class CatholicMonk extends Monk {
    @Override
    public void description() {
        System.out.println("Я католический монах");
    }
}
B) 修道院クラスに変更を加えます。
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;
    }
}
そのため、新しいタイプのモンクが導入されるたびに、新しいクラスを作成し、既存のクラスを編集する必要があります。 この場合、私たちの修道院クラスを何らかの形で変化から「カプセル化」するには何ができるでしょうか。Factory Method パターンを使用してみることができます。 どのように見えるか A) 修道士クラスはそのままにしておきますが、おそらく英国国教会の修道士を追加します (修道生活を持っているのはカトリック教徒と正教会のキリスト教徒だけではありません)。
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) 修道院クラスを次のように変更しましょう(クラスとそのメソッドを抽象化しましょう)。ここでは単にFactory メソッドを使用します。
public abstract class Monastery {
    protected abstract Monk createMonk();
}
そして、メソッド実装を使用して子クラスを作成します。
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) コードを確認しましょう
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();
    }
}
Я православный монах
Я католический монах
Я англиканский монах
それらの。ここでわかるように、新しいタイプの僧侶を追加するときに、既存のクラスを変更する必要はありませんが、必要な場合にのみ、新しいクラス (特定の僧院と僧侶のクラス) を追加します。おそらく誰かが、Monk クラスの最初からあった description メソッドもFactoryであることにすでに気づいているかもしれません :) ファクトリ メソッドの定義には、パターンがオブジェクトを作成するためのインターフェイスを定義していると書かれていましたが、何も作成しませんでした。ただし、Monastery クラスをインターフェイスとして作成し、それを特定の実装で実装することもできます。これは広義の「インターフェース」という言葉を指します。この定義では、 サブクラスが作成するインスタンスのクラスを選択できるとも述べられています。ここでは、サブクラス (子クラス) がこのメソッドを実装していることがわかります (つまり、モンク オブジェクトを作成する権限がサブクラスに委任されています)。ここでプログラムを少し拡張して、宗派ごとに異なる僧侶が存在する可能性を紹介しましょう。たとえば、正教会では、修道院と修道院に関する正教会の立場(2017年11月29日から12月2日のロシア正教会司教評議会で採択)に基づいて、修道士には2つのタイプがあると結論付けることができます。 : - より少ないスキーマ (マントル)。- スキーマ (グレート スキーマ)。「準備段階」もありますが、人々は修道誓願を立てていないため、修道士(トルドニク、修練者、リャソフォールまたは修道士)とは見なされません。したがって、それらは考慮していません。この場合に何が得られるか: A) Factory メソッドを使用した修道院クラス (簡略化するために、今は正統派の修道院生活に焦点を当てましょう) :
public abstract class Monastery {
    protected abstract Monk createMonk(String type);
}
そして特定の修道院
public class OrthodoxMonastery extends Monastery {

    @Override
    protected Monk createMonk(String type) {
        return new OrthodoxMonk(type);
    }
}
B) モンククラスを修正しましょう:
public abstract class Monk {
    String kind;

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

    public abstract void description();
}
そして子クラス:
public class OrthodoxMonk extends Monk {
    public OrthodoxMonk(String kind) {
        super(kind);
    }

    @Override
    public void description() {
        System.out.println("Я православный монах - " + kind);
    }
}
C) コードを確認してみましょう:
public class Main {
    public static void main(String[] args) {
        Monastery monastery = new OrthodoxMonastery();
        monastery.createMonk("Мантийный монах").description();
        monastery.createMonk("Великосхимник").description();
    }
}
Я православный монах - Мантийный монах
Я православный монах — Великосхимник
このように、Factory Method パターンを使用することで、以前に作成したクラスを変更する必要がなく、僧侶のイメージ (種類) を拡張する際にも最小限のコードの変更が必要になります。カトリック修道士のすべての修道会と会衆を確認して追加してみましょう:) しかし、100 以上あるので、最も有名な 3 つに焦点を当てたほうがよいでしょう: 1) ベネディクト会 2) イエズス会 3) フランシスコ会 これを行うには、以前と同様に、正教会の僧侶の場合は、カトリックの僧侶の特定のクラスを実装する必要があります。
public class CatholicMonk extends Monk {
    public CatholicMonk(String kind) {
        super(kind);
    }

    @Override
    public void description() {
        System.out.println("Я католический монах - " + kind);
    }
}
そして修道院クラス:
public class CatholicMonastery extends Monastery {

    @Override
    protected Monk createMonk(String type) {
        return new CatholicMonk(type);
    }
}
コードを確認してください:
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();
    }
}
Я православный монах - Мантийный монах
Я православный монах - Великосхимник
Я католический монах - Бенедиктинец
Я католический монах - Иезуит
Я католический монах - Францисканец
このパターンで終わりにしましょう。 これらすべてのタイプのモンクを事前に E-num クラスに追加することもできますが、コードを簡素化するために、モンクを省略して実行します。 Abstract Factory パターンの時間です。僧侶がいるから、彼らに服やロザリオなどを作ることができる。衣服から始めましょう。つまり、最初の定義に戻ると、 衣服は相互接続または相互依存するオブジェクトのファミリーになります。まずは、僧侶のタイプごとに僧衣が異なるという問題から始めましょう。仏教も追加すると、まったく異なります:) これを行うには、必要な衣服を作成する実装のファクトリインターフェイスを作成できます。したがって A) 衣服を作るための工場を作ります
public interface MonkFactory {
    Clothing createClothing();
}
とその実装
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();
    }
}
まあ、仏教の僧侶のことも忘れないでください:)
public class BuddhistMonkFactory implements MonkFactory {

    @Override
    public Clothing createClothing() {
        return new BuddhistClothing();
    }
}
B) 服装クラスを作成します (簡単にするために、僧侶の服装の重要な要素を取り上げます。詳細は説明しません)。
public abstract class Clothing {
    private String name;

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

    public String getName() {
        return name;
    }
}
そして子供クラス
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) 次に、僧侶が服を着られるようにクラスを変更します。
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) 修道院クラスには Factory メソッドが含まれています
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);
}
私たちの実装は変わっていません
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) 結果を確認します。
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();
    }
}
Я православный монах - Мантийный монах
Моя одежда - Мантия
Я католический монах - Иезуит
Моя одежда - Ряса с капюшоном
Я англиканский монах - Бенедиктинец
Моя одежда - Ряса
Я буддийский монах - Монах
Моя одежда - Кашая
衣服を作る工場が順調に稼働し始めた。修道士が祈りを成功させるための装備(数珠など)の生産を工場に追加できるようになりました。しかし、2 つのパターンを併用することは可能でしょうか?という疑問が残ります。もちろんできます:) プロジェクトの最終バージョンを作成して、ヒンズー教の僧侶を追加してみましょう: A) 工場で「スター工場」のように聞こえる僧侶が作成されるようになりました:
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) 修道院クラス + 修道院クラスの具体的な実装は必要ありません。それらはファクトリによって実装されます (逆に、それらを残してファクトリを削除することもできますが、本質的には、ファクトリの代わりに単にファクトリが存在するだけになります)この場合、修道院は抽象クラスではなくインターフェイスにする必要があります)。そして、アプリケーション クラスを追加します。
public class Application {

    public Monk create(MonkFactory monkFactory, String type) {
        Monk monk = monkFactory.createMonk(type);
        monk.prepare(monkFactory);
        return monk;
    }
}
B) モンクには次の内容が含まれています
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);
}
実装にはファクトリ メソッドが含まれており、ファクトリを使用して実装されます。
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) そして確認してみましょう:
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();
    }
}
Я православный монах - Мантийный монах
Моя одежда - Мантия
Я католический монах - Иезуит
Моя одежда - Ряса с капюшоном
Я англиканский монах - Бенедиктинец
Моя одежда - Ряса
Я буддийский монах - Монах
Моя одежда - Кашая
Я индуистский монах - Саньяси
Моя одежда - Почти ничего, тепло же :)
結論として、Factory メソッドはサブクラスに実装された未実装のメソッドを持つ抽象クラスを使用し、Abstract Factory はインターフェイスを使用し、実装 (この場合はモンクの作成) は実装されたクラスで行われたことがわかります。このインターフェース。
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION