JavaRush /Java Blog /Random-JA /デザインパターン: AbstractFactory

デザインパターン: AbstractFactory

Random-JA グループに公開済み
こんにちは!今日は引き続きデザイン パターンを学習し、抽象ファクトリーについて話します。 デザインパターン: AbstractFactory - 1講義中に行うこと:
  • 抽象ファクトリーとは何なのか、そしてこのパターンがどのような問題を解決するのかについて説明しましょう。
  • ユーザー インターフェイスを使用してコーヒーを注文するためのクロスプラットフォーム アプリケーションのフレームワークを作成します。
  • このパターンを使用する手順を図とコードで学習してみましょう。
  • おまけとして、講義にはイースターエッグが隠されています。これを利用して、Java を使用してオペレーティング システムの名前を決定し、結果に応じて何らかのアクションを実行する方法を学びます。
このパターンを完全に理解するには、次のトピックをよく理解する必要があります。
  • Java の継承。
  • Java の抽象クラスとメソッド。

抽象ファクトリー パターンはどのような問題を解決しますか?

抽象ファクトリは、他のファクトリ パターンと同様に、新しいオブジェクトの作成を正しく構成するのに役立ちます。その助けを借りて、相互接続されたオブジェクトのさまざまなファミリーの「リリース」を管理します。相互に関連するオブジェクトのさまざまなファミリー...それは何ですか? 心配しないでください。実際には、すべてが思っているよりも簡単です。関連するオブジェクトのファミリーとは何でしょうか? あなたと私が戦略を開発していて、その中にいくつかの戦闘ユニットがあると仮定します。
  • 歩兵;
  • 騎兵;
  • 射手。
これらのタイプの戦闘ユニットは同じ軍隊に所属するため、互いに関連しています。上記のカテゴリは、相互に関連するオブジェクトのファミリーであると言えます。それは解決しました。ただし、抽象ファクトリー パターンは、相互接続されたオブジェクトのさまざまなファミリーの作成を組織化するために使用されます。ここでも複雑なことは何もありません。戦略の例を続けてみましょう。彼らは通常、いくつかの異なる対立する側面を持っています。異なる側の戦闘ユニットは外観が大きく異なる場合があります。ローマ軍の歩兵、騎手、射手は、バイキングの歩兵、騎手、射手とは異なります。戦略の枠組み内では、さまざまな軍隊の兵士は、相互に接続されたオブジェクトのさまざまなファミリーです。プログラマーのミスで、ナポレオン時代のフランス軍の軍服を着た兵士が、マスケット銃を構えてローマの歩兵の中を歩き回っていたら面白いだろう。このような問題を解決するには、抽象的な工場設計パターンが必要です。いいえ、タイムトラベルの当惑の問題ではなく、相互に接続されたオブジェクトのさまざまなグループの作成の問題です。抽象ファクトリーは、すべての既存の製品 (ファミリー オブジェクト) を作成するためのインターフェイスを提供します。通常、抽象ファクトリには複数の実装があります。それぞれが、いずれかのバリエーションの製品を作成する責任を負います。戦略の一部として、抽象的な歩兵、射手、騎兵を作成する抽象ファクトリーと、このファクトリーの実装を用意します。ローマの軍団兵を作成する工場と、たとえばカルタゴの戦士を作成する工場です。抽象化は、このパターンの最も重要な原則です。ファクトリ クライアントは、抽象インターフェイスを通じてのみ、ファクトリ クライアントと製品を操作します。したがって、現在作成している戦士の種類について考える必要はなく、この責任を抽象ファクトリーの特定の実装に移します。

私たちはコーヒーショップの自動化を続けています

前回の講義では、ファクトリーメソッドのパターンを学び、その助けを借りてコーヒービジネスを拡大し、いくつかの新しいコーヒー販売拠点を開設することができました。今日も私たちはビジネスを近代化するための取り組みを続けます。抽象的なファクトリー パターンを使用して、オンラインでコーヒーを注文するための新しいデスクトップ アプリケーションの基礎を築きます。デスクトップ用のアプリケーションを作成するときは、常にクロスプラットフォームについて考慮する必要があります。私たちのアプリケーションは macOS と Windows の両方で動作するはずです (ネタバレ: Linux については宿題として残しておきます)。私たちのアプリケーションはどのようなものになるでしょうか? 非常に単純です。これは、テキスト フィールド、選択フィールド、ボタンで構成されるフォームになります。さまざまなオペレーティング システムを使用した経験がある場合は、Windows ではボタンのレンダリングが Mac とは異なることに間違いなく気づいているでしょう。他のことと同じように…それでは、始めましょう。すでにお分かりかと思いますが、製品ファミリーの役割には、グラフィカル インターフェイス要素があります。
  • ボタン。
  • テキストフィールド。
  • 選択用のフィールド。
免責事項。onClick各インターフェース内で、 、onValueChanged、 などのメソッドを定義できますonInputChanged。それらの。このメソッドを使用すると、さまざまなイベント (ボタンのクリック、テキストの入力、選択ボックスでの値の選択) を処理できるようになります。サンプルに負荷をかけすぎず、ファクトリ パターンをより視覚的に理解できるようにするために、これらすべては意図的に省略されています。製品の抽象インターフェイスを定義しましょう。
public interface Button {}
public interface Select {}
public interface TextField {}
オペレーティング システムごとに、そのオペレーティング システムのスタイルでインターフェイス要素を作成する必要があります。私たちは Windows と MacOS 向けに書いています。Windows 用の実装を作成しましょう。
public class WindowsButton implements Button {
}

public class WindowsSelect implements Select {
}

public class WindowsTextField implements TextField {
}
MacOS でも同じです:
public class MacButton implements Button {
}

public class MacSelect implements Select {
}

public class MacTextField implements TextField {
}
素晴らしい。これで、既存のすべての抽象製品タイプを作成する抽象ファクトリーを開始できます。
public interface GUIFactory {

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

}
完璧。ご覧のとおり、これまでのところ何も複雑なことはありません。そうすれば、すべてが同じように簡単になります。製品と同様に、OS ごとにファクトリーの異なる実装を作成します。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();
    }
}
メソッドとコンストラクター内にコンソール出力が追加され、その動作をさらに詳しく説明します。次に 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();
    }
}
注: 各メソッドは、そのシグネチャに従って、抽象型を返します。ただし、メソッド内で製品の具体的な実装を作成します。これは、特定のインスタンスの作成を制御する唯一の場所です。次に、フォーム クラスを作成します。これは、フィールドがインターフェイス要素である Java クラスです。
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();
    }
}
抽象ファクトリはフォーム コンストラクターに渡され、インターフェイス要素が作成されます。特定の OS 用のインターフェイス要素を作成できるように、必要なファクトリ実装をコンストラクターに渡します。
public class Application {
    private OrderCoffeeForm orderCoffeeForm;

    public void drawOrderCoffeeForm() {
        // Определим Name операционной системы, получив meaning системной проперти через 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();
    }
}
Windows でアプリケーションを実行すると、次の出力が得られます。

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
Mac では、出力は次のようになります。

Creating gui factory for macOS
Creating order coffee form
Creating TextField for macOS
Creating Select for macOS
Creating Button for macOS
Linux の場合:

Unknown OS, can't draw form :( 
さて、あなたと私は次の結論を導き出します。私たちは、特定の OS に適したインターフェイス要素を正確に作成する GUI アプリケーションのフレームワークを作成しました。私たちが作成したものを簡単に繰り返してみましょう。
  • 製品ファミリー: 入力フィールド、選択フィールド、ボタン。
  • Windows および macOS 向けのこの製品ファミリーのさまざまな実装。
  • 抽象的なファクトリー。その中で製品を作成するためのインターフェースを定義します。
  • 工場の 2 つの実装。それぞれが特定の製品ファミリーの作成を担当します。
  • フォーム。フィールドが抽象ファクトリを使用して必要な値を使用してコンストラクターで初期化される抽象インターフェイス要素である Java クラス。
  • アプリケーションクラス。その中で、ファクトリの必要な実装をコンストラクターに渡すフォームを作成します。
合計: 抽象ファクトリー パターンを実装しました。

アブストラクトファクトリー: 使用説明書

Abstract Factory は、特定の製品クラスに縛られることなく、さまざまな製品ファミリーの作成を管理するための設計パターンです。このテンプレートを使用する場合は、次のことを行う必要があります。
  1. 製品ファミリー自体を定義します。それらが 2 つあると仮定しましょう。
    • SpecificProductA1SpecificProductB1
    • SpecificProductA2SpecificProductB2
  2. ファミリ内の製品ごとに、抽象クラス (インターフェイス) を定義します。私たちの場合は次のようになります。
    • ProductA
    • ProductB
  3. 各製品ファミリー内で、各製品はステップ 2 で定義したインターフェイスを実装する必要があります。
  4. ステップ 2 で定義した各製品の作成メソッドを使用して、抽象ファクトリーを作成します。この場合、これらのメソッドは次のようになります。
    • ProductA createProductA();
    • ProductB createProductB();
  5. 抽象ファクトリーの実装を作成して、各実装が同じファミリーの製品の作成を制御できるようにします。これを行うには、抽象ファクトリの各実装内ですべての create メソッドを実装し、製品の具体的な実装が作成されてその中に返されるようにする必要があります。
以下は、上で説明した命令を示す UML 図です。 デザインパターン: AbstractFactory - 3次に、この命令のコードを書きましょう。
// Определим общие интерфейсы продуктов
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();
    }
}

宿題

マテリアルを統合するには、次の 2 つのことを行うことができます。
  1. コーヒー注文アプリケーションを Linux 上で動作するように改善しました。
  2. 独自の抽象ファクトリーを作成して、あらゆる戦略のユニットを生成します。これは、実際の軍隊を使った歴史戦略でも、オーク、ドワーフ、エルフを使ったファンタジーでも構いません。重要なのは、あなたがそれを面白いと思うことです。創造力を発揮してコンソールにピンを投稿し、楽しみながらパターンを学びましょう。
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION