nono blog
楽しい人生を送りたい!
ITスキル

pythonプログラム デザインパターン(Factory_Method)

デザインパターンの一つであるFactoryパターンについて忘備録をまとめます。

Factory_Methodパターンとは

(概要)工場のように大量の製品を作成するときのデザインパターン
・製品側と工場側で分けて考えて、工場側でテンプレートを作成する。
・テンプレートに応じて、工場を作成して、各上場で製品を作成する。

(イメージ)
工場 → 船工場 → 船作成
   → 車工場 → 車作成

(目的)
・オブジェクトの生成とオブジェクトの具体的な処理を分離することで、
柔軟にオブジェクトを利用でき、再利用性を高める。(単一責任の原則を満たす)

(仕組み)
・インターフェース(抽象クラス)で処理の骨組みを作り(工場)、サブクラスを用いてオブジェクトを作成する
・サブクラスに応じて、作成されるオブジェクトのタイプを変える(船工場から船作成)

(構成要素)
・Product      : 作成するオブジェクトの構成要素を定義するインターフェース(抽象クラス):工場の構成要素の原型
・ConcreteProduct : Productを具体化したクラス(複数作成):船工場、車工場、飛行機工場、、、
・Creator      : Productを生成する処理を定義したインターフェース(抽象クラス):工場の処理の原型
・ConcreteCreator : Creatorを具体化したConcreteProductを作成するクラス:船、車、、、
 (インターフェースの分離、依存性逆転の原則、などを満たしているものと考えられる)

Factory_Methodパターンのサンプルコード

FactroyパターンのPythonによるサンプルコードをメモします。

# factory_method.py

from abc import ABC, abstractmethod, abstractproperty


# Creator
class IFactory(ABC):

    def __init__(self):
        self.registered_owners = []

    def create(self, owner):
        self._owner = owner
        product = self._create_product()
        self._register_product(product)
        return product

    @abstractmethod
    def _create_product(self):
        pass

    @abstractmethod
    def _register_product(self, product):
        pass


# ConcreteCreator
class CarFactory(IFactory):

    # def _create_product(self):
    #     return Car(self._owner)

    # tagawa. 果たしてこういう拡張の仕方で良いのだろうか。。。なんか違う気がする。
    # IProduct(インターフェース)から、もっと拡張する必要があるのでは?
    def _create_product(self):
        if self._owner == 'Toyota':
            return ToyotaCar(self._owner)
        else:
            return Car(self._owner)

    def _register_product(self, product):
        self.registered_owners.append(product.owner)


class ShipFactory(IFactory):

    def _create_product(self):
        return Ship(self._owner)

    def _register_product(self, product):
        self.registered_owners.append(product.owner)


# Product
class IProduct(ABC):

    def __init__(self, owner):
        self._owner = owner

    @abstractmethod
    def use(self):
        pass

    @abstractproperty
    def owner(self):
        pass


# Concrete Product
class Car(IProduct):

    def use(self):
        print(f'{self.owner}: I drive a car.')

    @property
    def owner(self):
        return self._owner


# 
class ToyotaCar(IProduct):

    def use(self):
        print(f'{self.owner}: I drive a car.')

    def use_hybrid_car(self):
        print(f'{self.owner}: I drive a priuse. It is the hybrid car.')

    @property
    def owner(self):
        return self._owner


class Ship(IProduct):

    def use(self):
        print(f'{self.owner}: I drive a ship.')

    @property
    def owner(self):
        return self._owner


if __name__ == '__main__':
    car_factory = CarFactory()
    toyota_car = car_factory.create('Toyota')
    tesla_car = car_factory.create('Tesla')
    toyota_car.use()
    # tagawa
    toyota_car.use_hybrid_car()
    tesla_car.use()

    print(car_factory.registered_owners)

    ship_factory = ShipFactory()
    john_ship = ship_factory.create('John')
    mike_ship = ship_factory.create('Mike')
    john_ship.use()
    mike_ship.use()

    print(ship_factory.registered_owners)