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

## 目次
[● Adapter パターン](#-adapter-パターン)
[● Bridge パターン](#-bridge-パターン)
[● Composite パターン](#-composite-パターン)
[● Decorator パターン](#-decorator-パターン)
[● Facade パターン](#-facade-パターン)
[● Flyweight パターン](#-flyweight-パターン)
[● Proxy パターン](#-proxy-パターン)
[その他のデザインパターン](#その他のデザインパターン)

## <font color="DarkGray">●</font><font color="DeepSkyBlue"> Adapter パターン</font>

```python: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円
```
## <font color="DarkGray">●</font><font color="DeepSkyBlue"> Bridge パターン</font>

```python: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()

```
実行結果：
```
ブルー三角
黄色三角
黄色円
```
## <font color="DarkGray">●</font><font color="DeepSkyBlue"> Composite パターン</font>
```python: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
```
## <font color="DarkGray">●</font><font color="DeepSkyBlue"> Decorator パターン</font>

```python: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
```
## <font color="DarkGray">●</font><font color="DeepSkyBlue"> Facade パターン</font>

```python: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
```
## <font color="DarkGray">●</font><font color="DeepSkyBlue"> Flyweight パターン</font>

```python: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
```
## <font color="DarkGray">●</font><font color="DeepSkyBlue"> Proxy パターン</font>

```python: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で生成に関するデザインパターンを作成してみた](https://qiita.com/lxk/items/f62611a34005f1c087b0)
[Pythonで振る舞いに関するデザインパターンを作成してみた](https://qiita.com/lxk/items/9ff63940ace1a68205fe)

***