6
2

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-03-05

目次

● Adapter パターン
● Bridge パターン
● Composite パターン
● Decorator パターン
● Facade パターン
● Flyweight パターン
● Proxy パターン
その他のデザインパターン

Adapter パターン

Adapter.py
# ---------------------------------------------------------------------------------------
#                          Adapter パターン
# ---------------------------------------------------------------------------------------
# 互換性のないインタフェースを持つクラス同士を接続できるようにします

from abc import ABCMeta, abstractmethod


# 抽象的な製品
class Payment(metaclass=ABCMeta):
    @abstractmethod
    def pay(self, money):
        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))


# BankPayクラスはを編集しない理由があるとします。
class BankPay(object):
    def show_pay(self, money):
        print("銀行支払い:{0}円".format(money))


# クラスアダプタ(継承を用いる方法)
class NewBankPay(Payment, BankPay):
    def pay(self, money):
        self.show_pay(money)


# オブジェクトアダプタ(委譲を用いる方法)
class PaymentAdapter(Payment):
    def __init__(self, payment):
        self.payment = payment

    def pay(self, money):
        self.payment.show_pay(money)


if __name__ == '__main__':
    # クラスアダプタ
    print("--- 継承を用いる方法 ---")
    p1 = NewBankPay()
    p1.pay(1000)

    # オブジェクトアダプタ
    print("--- 委譲を用いる方法 ---")
    p2 = PaymentAdapter(BankPay())
    p2.pay(3000)

実行結果:

--- 継承を用いる方法 ---
銀行支払い:1000円
--- 委譲を用いる方法 ---
銀行支払い:3000円

Bridge パターン

Bridge.py
# ---------------------------------------------------------------------------------------
#                          Bridge パターン
# ---------------------------------------------------------------------------------------
# 抽象化と実現を分離して、継承関係を関連関係に変換することで、それぞれ、独立して変更できるようにします。
from abc import ABCMeta, abstractmethod


class ShapeInterface(metaclass=ABCMeta):
    def __init__(self, color):
        self.color = color

    @abstractmethod
    def draw(self):
        pass


class ColorInterface(metaclass=ABCMeta):
    @abstractmethod
    def print_info(self, shape):
        pass


class Triangle(ShapeInterface):
    shape_name = "三角"

    def draw(self):
        self.color.print_info(self)


class Circle(ShapeInterface):
    shape_name = ""

    def draw(self):
        self.color.print_info(self)


class Blue(ColorInterface):
    def print_info(self, shape):
        print("ブルー{0}".format(shape.shape_name))


class Yellow(ColorInterface):
    def print_info(self, shape):
        print("黄色{0}".format(shape.shape_name))


if __name__ == '__main__':
    # ブルー三角というオブジェクトを作成
    tb = Triangle(Blue())
    tb.draw()
    # 黄色三角というオブジェクトを作成
    ty = Triangle(Yellow())
    ty.draw()
    # 黄色円というオブジェクトを作成
    cy = Circle(Yellow())
    cy.draw()

実行結果:

ブルー三角
黄色三角
黄色円

Composite パターン

Composite.py
# ---------------------------------------------------------------------------------------
#                          Composite パターン
# ---------------------------------------------------------------------------------------
# 容器と中身を同一視することで、再帰的な構造を構築できるようにします。

class Component:
    def __init__(self, name):
        self.name = name
        self.children = []

    def add(self, comp):
        self.children.append(comp)

    def remove(self, comp):
        self.remove(comp)

    def show(self, depth):
        buf = ''
        for i in range(depth):
            buf += '-----'
        print(buf + self.name)
        for comp in self.children:
            comp.show(depth + 1)


class Leaf(Component):
    def add(self, comp):
        print('追加できません')

    def remove(self, comp):
        print('削除できません')


class Node(Component):
    pass


if __name__ == '__main__':
    root = Node('Dドライブ')
    root.add(Leaf('ファイル1'))
    root.add(Leaf('ファイル2'))
    fd1 = Node('※フォルダー1')
    fd2 = Node('※フォルダー2')
    fd3 = Node('※フォルダー3')
    root.add(fd1)
    root.add(fd2)
    root.add(fd3)
    fd1.add(Leaf('Fd1のファイル11'))
    fd1.add(Leaf('Fd1のファイル12'))
    fd2.add(Leaf('Fd2のファイル21'))
    root.show(1)

実行結果:

-----Dドライブ
----------ファイル1
----------ファイル2
----------※フォルダー1
---------------Fd1のファイル11
---------------Fd1のファイル12
----------※フォルダー2
---------------Fd2のファイル21
----------※フォルダー3

Decorator パターン

Decorator.py
# ---------------------------------------------------------------------------------------
#                          Decorator パターン
# ---------------------------------------------------------------------------------------
# 構造を変更せずに、既存のオブジェクトに新しい機能を追加できるようにします。


class Foo:
    def method1(self):
        print('Foo:method1')

    def method2(self):
        print('Foo:method2')

    def method3(self):
        print('Foo:method3')


class FooDecorator:
    def __init__(self, foo):
        self.foo = foo

    def method2(self):
        print('.' * 20)
        print('FooDecorator:method2')
        self.foo.method2()
        print('-' * 20)

    def __getattr__(self, item):
        return getattr(self.foo, item)


if __name__ == '__main__':
    fd = FooDecorator(Foo())
    fd.method2()
    fd.method1()
    fd.method3()

実行結果:

....................
FooDecorator:method2
Foo:method2
--------------------
Foo:method1
Foo:method3

Facade パターン

Facade.py
# ---------------------------------------------------------------------------------------
#                          Facade パターン
# ---------------------------------------------------------------------------------------
# 複雑なサブシステム内の機能を利用するため、シンプルなインターフェースを提供します。

class SubSystem1:
    def method_a(self):
        print('Run SubSystem1.method_a')


class SubSystem2:
    def method_b(self):
        print('Run SubSystem2.method_b')


class SubSystem3:
    def method_c(self):
        print('Run SubSystem3.method_c')


class FacadeSystem:
    def __init__(self):
        self.subsystem1 = SubSystem1()
        self.subsystem2 = SubSystem2()
        self.subsystem3 = SubSystem3()

    def method(self):
        self.subsystem1.method_a()
        self.subsystem2.method_b()
        self.subsystem3.method_c()


if __name__ == '__main__':
    facade = FacadeSystem()
    facade.method()

実行結果:

Run SubSystem1.method_a
Run SubSystem2.method_b
Run SubSystem3.method_c

Flyweight パターン

Flyweight.py
# ---------------------------------------------------------------------------------------
#                          Flyweight パターン
# ---------------------------------------------------------------------------------------
# 生成済みのオブジェクトを共有し、余分なオブジェクトの生成を防止します。

class Flyweight:
    def __init__(self, name):
        self.name = name

    def show(self):
        print('Flyweight Name: {0}'.format(self.name))


class FlyweightFactory:
    def __init__(self):
        self.objs = {}

    def get_object(self, objname):
        # 生成済みのオブジェクトを再利用
        obj = self.objs.get(objname)
        if not obj:
            obj = Flyweight(objname)
            self.objs[objname] = obj
        return obj

    def display(self):
        for obj in self.objs.values():
            obj.show()
        print('オブジェクト数: {0}'.format(len(self.objs)))


if __name__ == '__main__':
    flyweight_factory = FlyweightFactory()
    f1 = flyweight_factory.get_object('AA')
    f2 = flyweight_factory.get_object('BB')
    f3 = flyweight_factory.get_object('AA')

    flyweight_factory.display()

実行結果:

Flyweight Name: AA
Flyweight Name: BB
オブジェクト数: 2

Proxy パターン

Proxy.py
# ---------------------------------------------------------------------------------------
#                          Proxy パターン
# ---------------------------------------------------------------------------------------
# オブジェクトへのアクセスを制御するために、そのオブジェクトの代理を提供します。

from abc import ABCMeta, abstractmethod


class Staff(metaclass=ABCMeta):
    @abstractmethod
    def work(self):
        pass


class RealStaff(Staff):
    def work(self):
        print('RealStaff:work')


class ProxyStaff(Staff):
    def __init__(self):
        self.real_staff = None

    def work(self):
        if self.real_staff is None:
            self.real_staff = RealStaff()
        print('ProxyStaff:work')
        self.real_staff.work()


if __name__ == '__main__':
    proxy_staff = ProxyStaff()
    proxy_staff.work()

実行結果:

ProxyStaff:work
RealStaff:work

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

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


6
2
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
6
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?