1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Abstract Factory パターンを世界の料理で理解する

Posted at

はじめに

プログラミングのデザインパターンは、実際の生活の例を用いると非常に理解しやすくなります。今回は、Abstract Factoryパターンを、世界各国の料理を例にPythonで実装して説明します。この例を通じて、Abstract Factoryパターンの柔軟性と拡張性を理解しましょう。

Abstract Factoryパターンとは

image.png

Abstract Factoryパターンは、関連する一連のオブジェクト(この場合は料理)を、その具体的な種類を指定せずに生成するためのパターンです。簡単に言えば、「料理を作る方法」を定義しておいて、実際にどの国の料理を作るかは後で決められるようにする、というものです。

なぜAbstract Factoryパターンを使うのか

  1. 柔軟性: 様々な国の料理を、同じ手順で作れるようになります。
  2. 一貫性: 関連する料理(前菜、主菜、デザートなど)を一緒に作ることで、一つの国の料理としての一貫性を保てます。
  3. 拡張性: 新しい国の料理を追加するのが簡単になります。

Pythonによる実装例の解説

抽象クラスの定義

まず、料理の構成要素とファクトリーの抽象クラスを定義します。

from abc import ABC, abstractmethod

class Appetizer(ABC):
    @abstractmethod
    def prepare(self):
        pass

class MainCourse(ABC):
    @abstractmethod
    def prepare(self):
        pass

class Dessert(ABC):
    @abstractmethod
    def prepare(self):
        pass

class CuisineFactory(ABC):
    @abstractmethod
    def create_appetizer(self):
        pass

    @abstractmethod
    def create_main_course(self):
        pass

    @abstractmethod
    def create_dessert(self):
        pass

これらの抽象クラスは、それぞれの国の料理が実装すべきメソッドを定義しています。

具体的な実装

次に、日本、イタリア、インドの料理それぞれの具体的な実装を行います。

# 日本料理の具体クラス
class JapaneseAppetizer(Appetizer):
    def prepare(self):
        return "お刺身を盛り付けました"

# ... 他の日本料理クラスも同様に実装 ...

class JapaneseCuisineFactory(CuisineFactory):
    def create_appetizer(self):
        return JapaneseAppetizer()

    # ... 他のメソッドも同様に実装 ...

# イタリア料理の具体クラス
class ItalianAppetizer(Appetizer):
    def prepare(self):
        return "ブルスケッタを作りました"

# ... 他のイタリア料理クラスも同様に実装 ...

# インド料理の具体クラス
class IndianAppetizer(Appetizer):
    def prepare(self):
        return "サモサを揚げました"

# ... 他のインド料理クラスも同様に実装 ...

各国の料理に対して、具体的な料理の内容とそれらを生成するファクトリークラスを実装しています。

クライアント関数

最後に、これらのファクトリーを使用して実際に料理を準備する関数を定義します。

def prepare_meal(factory):
    appetizer = factory.create_appetizer()
    main_course = factory.create_main_course()
    dessert = factory.create_dessert()

    print("食事の準備:")
    print(appetizer.prepare())
    print(main_course.prepare())
    print(dessert.prepare())

この関数は、どの国の料理ファクトリーが渡されても同じように動作します。これがAbstract Factoryパターンの真髄です。

実行例

if __name__ == "__main__":
    print("日本料理:")
    japanese_factory = JapaneseCuisineFactory()
    prepare_meal(japanese_factory)

    print("\nイタリア料理:")
    italian_factory = ItalianCuisineFactory()
    prepare_meal(italian_factory)

    print("\nインド料理:")
    indian_factory = IndianCuisineFactory()
    prepare_meal(indian_factory)

この部分で実際に各国の料理の準備を行います。出力は以下のようになります:

日本料理:
食事の準備:
お刺身を盛り付けました
天ぷらを揚げました
抹茶アイスを用意しました

イタリア料理:
食事の準備:
ブルスケッタを作りました
パスタを茹でました
ティラミスを用意しました

インド料理:
食事の準備:
サモサを揚げました
カレーを煮込みました
ラッシーを作りました

Abstract Factoryパターンの利点

  1. 柔軟性: 新しい国の料理を追加する際、既存のコードを変更せずに新しいファクトリーとクラスを追加するだけで済みます。
  2. 一貫性: 各国の料理セットの構成要素が適切に組み合わされます。例えば、日本のデザートがイタリアの前菜と組み合わさることはありません。
  3. カプセル化: 具体的な料理の作り方の詳細は、各クラス内に隠蔽されています。

実際の応用例

Abstract Factoryパターンは、以下のような状況で特に有用です:

  1. クロスプラットフォームのUIライブラリ:Windows、Mac、Linuxなど、異なるOSに対応するUIコンポーネントを作成する際に使用できます。
  2. データベース接続ライブラリ:MySQL、PostgreSQL、SQLiteなど、異なるデータベースシステムに対応するコネクションやクエリビルダーを作成する際に活用できます。
  3. ゲーム開発:異なる難易度レベルや異なるテーマの敵キャラクター、アイテムなどを生成する際に使用できます。

まとめ

image.png

Abstract Factoryパターンを世界の料理の例で実装することで、このパターンの柔軟性と拡張性がより明確になりました。このパターンを使用することで、新しい種類のオブジェクト(この場合は新しい国の料理)を追加する際に、既存のコードを変更せずに済むという大きな利点があります。

プログラミングの世界でも、適切な「レシピ」(デザインパターン)を選ぶことで、より柔軟で保守しやすいシステムを作ることができます。次回あなたがプログラムを書く際、この世界の料理の例を思い出してAbstract Factoryパターンの適用を検討してみてください。

実装(全部)

from abc import ABC, abstractmethod

# 抽象クラス
class Appetizer(ABC):
    @abstractmethod
    def prepare(self):
        pass

class MainCourse(ABC):
    @abstractmethod
    def prepare(self):
        pass

class Dessert(ABC):
    @abstractmethod
    def prepare(self):
        pass

class CuisineFactory(ABC):
    @abstractmethod
    def create_appetizer(self):
        pass

    @abstractmethod
    def create_main_course(self):
        pass

    @abstractmethod
    def create_dessert(self):
        pass

# 日本料理の具体クラス
class JapaneseAppetizer(Appetizer):
    def prepare(self):
        return "お刺身を盛り付けました"

class JapaneseMainCourse(MainCourse):
    def prepare(self):
        return "天ぷらを揚げました"

class JapaneseDessert(Dessert):
    def prepare(self):
        return "抹茶アイスを用意しました"

class JapaneseCuisineFactory(CuisineFactory):
    def create_appetizer(self):
        return JapaneseAppetizer()

    def create_main_course(self):
        return JapaneseMainCourse()

    def create_dessert(self):
        return JapaneseDessert()

# イタリア料理の具体クラス
class ItalianAppetizer(Appetizer):
    def prepare(self):
        return "ブルスケッタを作りました"

class ItalianMainCourse(MainCourse):
    def prepare(self):
        return "パスタを茹でました"

class ItalianDessert(Dessert):
    def prepare(self):
        return "ティラミスを用意しました"

class ItalianCuisineFactory(CuisineFactory):
    def create_appetizer(self):
        return ItalianAppetizer()

    def create_main_course(self):
        return ItalianMainCourse()

    def create_dessert(self):
        return ItalianDessert()

# インド料理の具体クラス
class IndianAppetizer(Appetizer):
    def prepare(self):
        return "サモサを揚げました"

class IndianMainCourse(MainCourse):
    def prepare(self):
        return "カレーを煮込みました"

class IndianDessert(Dessert):
    def prepare(self):
        return "ラッシーを作りました"

class IndianCuisineFactory(CuisineFactory):
    def create_appetizer(self):
        return IndianAppetizer()

    def create_main_course(self):
        return IndianMainCourse()

    def create_dessert(self):
        return IndianDessert()

# クライアント関数
def prepare_meal(factory):
    appetizer = factory.create_appetizer()
    main_course = factory.create_main_course()
    dessert = factory.create_dessert()

    print("食事の準備:")
    print(appetizer.prepare())
    print(main_course.prepare())
    print(dessert.prepare())

# メイン処理
if __name__ == "__main__":
    print("日本料理:")
    japanese_factory = JapaneseCuisineFactory()
    prepare_meal(japanese_factory)

    print("\nイタリア料理:")
    italian_factory = ItalianCuisineFactory()
    prepare_meal(italian_factory)

    print("\nインド料理:")
    indian_factory = IndianCuisineFactory()
    prepare_meal(indian_factory)
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?