0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Pythonで生成に関するデザインパターンを作成してみた

Last updated at Posted at 2022-02-19

目次

● Factory Method パターン
● Abstract Factory パターン
● Builder パターン
● Singleton パターン
● Prototype パターン
その他のデザインパターン

Factory Method パターン

FactoryMethod.py
# ---------------------------------------------------------------------------------------
#                          Factory Method パターン
# ---------------------------------------------------------------------------------------
# オブジェクトを作成するためのインターフェースを定義し、サブクラスが作成する具象クラスを決定します。
from abc import ABCMeta, abstractmethod


# 抽象的な製品
class Payment(metaclass=ABCMeta):
    @abstractmethod
    def pay(self, money):
        pass


# 抽象的な工場
class PaymentFactory(metaclass=ABCMeta):
    @abstractmethod
    def create_payment(self):
        pass


# 具象クラス(製品)
class VisaPay(Payment):
    def pay(self, money):
        print("Visa支払い:{0}円".format(money))


# 具象クラス(製品)
class MasterPay(Payment):
    def pay(self, money):
        print("Master支払い:{0}円".format(money))


# 具象クラス(工場)
class VisaFactory(PaymentFactory):
    def create_payment(self):
        return VisaPay()


# 具象クラス(工場)
class MasterFactory(PaymentFactory):
    def create_payment(self):
        return MasterPay()


if __name__ == '__main__':
    # Client(利用側)
    # 利用側は利用されるVisaPayなどに依存しません。
    py = VisaFactory()
    p = py.create_payment()
    p.pay(1000)

    py = MasterFactory()
    p = py.create_payment()
    p.pay(2000)

実行結果:

Visa支払い:1000円
Master支払い:2000円

Abstract Factory パターン

AbstractFactory.py
# ---------------------------------------------------------------------------------------
#                          Abstract Factory パターン
# ---------------------------------------------------------------------------------------
# ファクトリクラスインターフェイスを定義し、サブファクトリクラスで互いに関連する一連オブジェクト群を間違いなく作成します。

from abc import ABCMeta, abstractmethod


# 抽象的なCPU
class CPU(metaclass=ABCMeta):
    @abstractmethod
    def show_cpu(self):
        pass


# 抽象的なOS
class OS(metaclass=ABCMeta):
    @abstractmethod
    def show_os(self):
        pass


# 抽象的な工場
class SmartphoneBase(metaclass=ABCMeta):
    @abstractmethod
    def make_cpu(self):
        pass

    @abstractmethod
    def make_os(self):
        pass


# ----------具象CPU--------
class AppleCPU(CPU):
    def show_cpu(self):
        print("Apple  CPU")


class SnapdragonCPU(CPU):
    def show_cpu(self):
        print("Snapdragon CPU")


# ----------具象OS--------
class IOS(OS):
    def show_os(self):
        print("IOS モバイルオペレーティングシステム")


class Android(OS):
    def show_os(self):
        print("Android モバイルオペレーティングシステム")


# ----------具象工場--------
class AppleFactory(SmartphoneBase):
    def make_cpu(self):
        return AppleCPU()

    def make_os(self):
        return IOS()


class SamsungFactory(SmartphoneBase):
    def make_cpu(self):
        return SnapdragonCPU()

    def make_os(self):
        return Android()


# ------------ Client(利用側) ------------
class Smartphone(object):
    def __init__(self, cpu, os):
        self.cpu = cpu
        self.os = os

    def show_info(self):
        print("スマートフォン情報:")
        self.cpu.show_cpu()
        self.os.show_os()


def make_smartphone(factory):
    cpu = factory.make_cpu()
    os = factory.make_os()
    return Smartphone(cpu, os)


if __name__ == '__main__':
    p1 = make_smartphone(AppleFactory())
    p1.show_info()

    p2 = make_smartphone(SamsungFactory())
    p2.show_info()

実行結果:

スマートフォン情報:
Apple  CPU
IOS モバイルオペレーティングシステム
スマートフォン情報:
Snapdragon CPU
Android モバイルオペレーティングシステム

Builder パターン

Builder.py
# ---------------------------------------------------------------------------------------
#                          Builder パターン
# ---------------------------------------------------------------------------------------
# 連鎖呼び出しで、複雑なオブジェクトを段階的に構築します


def return_this(func):
    def wrapper(self, *args, **kwargs):
        func(self, *args, **kwargs)
        return self

    return wrapper


class Computer:

    def __init__(self):
        self.cpu = ''
        self.usbCount = 0
        self.display = ''
        self.builder = Computer.Builder(self)

    def show_info(self):
        print("cpu: {0}, usbCount: {1}, display: {2}".format(self.cpu, str(self.usbCount), self.display))

    # 内部クラス
    class Builder:
        def __init__(self, computer):
            self.cpu = computer.cpu
            self.usbCount = computer.usbCount
            self.display = computer.display

        @return_this
        def set_cpu(self, cpu):
            self.cpu = cpu

        @return_this
        def set_usbCount(self, usbCount):
            self.usbCount = usbCount

        @return_this
        def set_display(self, display):
            self.display = display

        def build(self):
            newComputer = Computer()
            newComputer.cpu = self.cpu
            newComputer.usbCount = self.usbCount
            newComputer.display = self.display
            newComputer.builder = self
            return newComputer


# ------------ Client(利用側) ------------

class Computer001Builder:
    def __init__(self):
        self.computer = Computer().builder \
            .set_cpu("Core i7-6700") \
            .set_usbCount(2) \
            .set_display("ASUS VZ249HE") \
            .build()

    def get_computer(self):
        return self.computer


if __name__ == '__main__':
    print("-----PC製品-----")
    c001 = Computer001Builder().get_computer()
    c001.show_info()

    print("-----自作PC-----")
    # デフォルト構成
    # 連鎖呼び出しで、PC製品というオブジェクトを段階的に構築します
    selfMakeComputer = Computer().builder \
        .set_cpu("Core i5-6500") \
        .set_usbCount(1) \
        .set_display("Dell U2720QM") \
        .build()
    selfMakeComputer.show_info()

    # 構成変更
    print("-----自作PCにUSB増設-----")
    selfMakeComputer = selfMakeComputer.builder.set_usbCount(5).build()
    selfMakeComputer.show_info()

実行結果:

-----PC製品-----
cpu: Core i7-6700, usbCount: 2, display: ASUS VZ249HE
-----自作PC-----
cpu: Core i5-6500, usbCount: 1, display: Dell U2720QM
-----自作PCにUSB増設-----
cpu: Core i5-6500, usbCount: 5, display: Dell U2720QM

Singleton パターン

Singleton.py
# ---------------------------------------------------------------------------------------
#                          Singleton パターン
# ---------------------------------------------------------------------------------------
# インスタンスを1つしか生成できないクラスを作成します。

class SingletonBase:
    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, "_instance"):
            cls._instance = super(SingletonBase, cls).__new__(cls)
        return cls._instance


class SingletonA(SingletonBase):
    def __init__(self, x):
        self.x = x


if __name__ == '__main__':
    s1 = SingletonA(100)
    s2 = SingletonA(300)
    print(s1.x)
    print(s2.x)
    print("s1のアドレス:{0}, s2のアドレス:{1}".format(id(s1),  id(s2)))

実行結果:

300
300
s1のアドレス:2060572639088, s2のアドレス:2060572639088

Prototype パターン

Prototype.py
# ---------------------------------------------------------------------------------------
#                          Prototype パターン
# ---------------------------------------------------------------------------------------
# オブジェクトを複製します
class ProtoType:
    def __init__(self, id, name):
        super().__init__()
        self.id = id
        self.name = name

    def clone(self):
        import copy
        return copy.deepcopy(self)


if __name__ == '__main__':
    original = ProtoType(100, "テスト名称")
    o_copy = original.clone()
    print('original.id: {}  original.name: {}'.format(original.id, original.name))
    print('o_copy.id: {}  o_copy.name: {}'.format(o_copy.id, o_copy.name))
    print('オブジェクト(original)のID: {} '.format(id(original)))
    print('オブジェクト(o_copy)のID: {} '.format(id(o_copy)))

実行結果:

original.id: 100  original.name: テスト名称
o_copy.id: 100  o_copy.name: テスト名称
オブジェクト(original)のID: 1828390518688 
オブジェクト(o_copy)のID: 1828390518208 

その他のデザインパターン

Pythonで構造に関するデザインパターンを作成してみた
Pythonで振る舞いに関するデザインパターンを作成してみた


0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?