Pythonで、デザインパターン「Adapter」を学ぶ

GoFのデザインパターンを学習する素材として、書籍「[増補改訂版Java言語で学ぶデザインパターン入門](https://www.hyuki.com/dp/)」が参考になるみたいですね。ただ、取り上げられている実例は、JAVAベースのため、自分の理解を深めるためにも、Pythonで同等のプラクティスに挑んでみました。

# ■ Adapter（アダプター・パターン）
Adapterパターン（アダプター・パターン）とは、GoF (Gang of Four; 4人のギャングたち) によって定義されたデザインパターンの1つである。Adapterパターンを用いると、既存のクラスに対して修正を加えることなく、インタフェースを変更することができる。Adapterパターンを実現するための手法として"**継承を利用した手法**"と"**委譲を利用した手法**"が存在する。

## UML class diagram
![W3sDesign_Adapter_Design_Pattern_UML.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103595/7e65457a-bb6b-7cff-5265-9ebfc4d4e20e.jpeg)


### 1. 継承を利用したAdapter
継承を利用したAdapterは、利用したいクラスのサブクラスを作成し、そのサブクラスに対して必要なインタフェースを実装することで実現される。
![inheritence.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103595/d1f60174-d1e1-d620-0566-2b04ebcdf431.png)


### 2. 委譲を利用したAdapter
委譲を利用したAdapterは、利用したいクラスのインスタンスを生成し、そのインスタンスを他クラスから利用することで実現される。
![delegation.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103595/a8943aab-6f32-c391-cbdc-c4ecebdb869a.png)
[(以上、ウィキペディア（Wikipedia）より引用)](https://ja.wikipedia.org/wiki/Adapter_パターン)

# ■ "Adapter"のサンプルプログラム
実際に、Adapterパターンを活用したサンプルプログラムを動かしてみて、次のような動作の様子を確認したいと思います。

- 文字列を、カッコでくくって表示する
- 文字列の前後に、*印をつけて表示する

```console
$ python Main.py 
(Hello)
*Hello*
```

# ■ サンプルプログラムの詳細
Gitリポジトリにも、同様のコードをアップしています。
https://github.com/ttsubo/study_of_design_pattern/tree/master/Adapter

- ディレクトリ構成

```console
.
├── Main.py
└── adapter
    ├── __init__.py
    ├── banner.py
    ├── print.py
    └── print_banner.py
```

## (1) Target（対象）の役
`Target`役は、インスタンスの振る舞いに関わるインタフェースを定めます。
サンプルプログラムでは、`Print`クラスが、この役を努めます。

```python:adapter/print.py
from abc import ABCMeta, abstractmethod

class Print(metaclass=ABCMeta):
    @abstractmethod
    def printWeak(self):
        pass

    @abstractmethod
    def printStrng(self):
        pass
```
## (2) Client（依頼者）の役
`Target`役のメソッドを使って、仕事をする役です。
サンプルプログラムでは、`startMain`メソッドが、この役を努めます。

```python:Main.py
from adapter.print_banner import PrintBanner

def startMain():
    p = PrintBanner("Hello")
    p.printWeak()
    p.printStrng()

if __name__ == '__main__':
    startMain()
```

## (3) Adaptee（適合される側）の役
`Adapter`役のなかで実際に動作するメソッドを、ここで実装します。
サンプルプログラムでは、`Banner`クラスが、この役を努めます。

```python:adapter/banner.py
class Banner(object):
    def __init__(self, string):
        self.__string = string

    def showWithParen(self):
        print("({0})".format(self.__string))

    def showWithAster(self):
        print("*{0}*".format(self.__string))
```

## (4) Adapter（適合する側）の役
`Adapter`役は、`Target`役のインタフェースを実装しているクラスです。
サンプルプログラムでは、`PrintBanner`クラスが、この役を努めます。
Adapterパターンを実現するための手法として、次の二つの手法が存在します。

- 継承を利用した手法
- 委譲を利用した手法

### □ 継承を利用したサンプルプログラム
```python:adapter/print_banner.py
from adapter.banner import Banner
from adapter.print import Print

class PrintBanner(Banner, Print):
    def __init__(self, string):
        super(PrintBanner, self).__init__(string)

    def printWeak(self):
        self.showWithParen()

    def printStrng(self):
        self.showWithAster()
```

### □ 委譲を利用したサンプルプログラム
```python:adapter/print_banner.py
from adapter.banner import Banner
from adapter.print import Print

class PrintBanner(Print):
    def __init__(self, string):
        self.__banner = Banner(string)

    def printWeak(self):
        self.__banner.showWithParen()

    def printStrng(self):
        self.__banner.showWithAster()
```

# ■ 参考URL
- [「Java言語で学ぶデザインパターン入門」を終えて(ない)](https://medium.com/since-i-want-to-start-blog-that-looks-like-men-do/java言語で学ぶデザインパターン入門-を終えて-ない-2cc9b34a30b2)
- [Adapterパターン from "tachikawa844の日記"](https://tachikawa844.hatenadiary.org/entry/20081219/1229682213)