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


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

■ Adapter(アダプター・パターン)

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

UML class diagram

1. 継承を利用したAdapter

継承を利用したAdapterは、利用したいクラスのサブクラスを作成し、そのサブクラスに対して必要なインタフェースを実装することで実現される。

2. 委譲を利用したAdapter

委譲を利用したAdapterは、利用したいクラスのインスタンスを生成し、そのインスタンスを他クラスから利用することで実現される。

(以上、ウィキペディア(Wikipedia)より引用)

■ "Adapter"のサンプルプログラム

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

  • 文字列を、カッコでくくって表示する
  • 文字列の前後に、*印をつけて表示する
$ python Main.py 
(Hello)
*Hello*

■ サンプルプログラムの詳細

Gitリポジトリにも、同様のコードをアップしています。
https://github.com/ttsubo/study_of_design_pattern/tree/master/Adapter

  • ディレクトリ構成
.
├── Main.py
└── adapter
    ├── __init__.py
    ├── banner.py
    ├── print.py
    └── print_banner.py

(1) Target(対象)の役

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

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メソッドが、この役を努めます。

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クラスが、この役を努めます。

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パターンを実現するための手法として、次の二つの手法が存在します。

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

□ 継承を利用したサンプルプログラム

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()

□ 委譲を利用したサンプルプログラム

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