Chap2 Adapter Pattern
Adapterパターンとは
- adapter:提供側と利用側の間に入り、両者をつなぐ(値を変換する)役割
- 電流の例であれば、「交流200ボルト」(提供側)と「直流12ボルト」(利用側)をつなぐACアダプターのようなもの
- Adapterパターンには2種類存在する
- パターン1:クラスによるAdapter(継承を利用する)
- パターン2:インスタンスによるAdapter(委譲を利用する)
どんなときに使えるのか
- すでに提供されている(実装されているクラス)のメソッドがそのままでは使えない時や使いづらい時に利用する
- 既存のクラスを継承もしくは委譲で利用するためすでに実装されている部分はテストしなくてすむ(テスト工数が減る)
- 既存のコードの書き換え(破壊的変更)をせずに機能を拡張できる
パターン1 クラスによるAdapter(継承を利用する)
Bannerクラス
- インスタンス生成時に表示する文字列をパラメータとして受ける
- メソッドによって表示するパターンが異なる
Banner
class Banner():
def __init__(self, string):
self._string = string
def show_with_pattern(self):
print("({})".format(self._string))
def show_with_aster(self):
print("*{}*".format(self._string))
Printインタフェース
- Mainクラスが利用するインタフェース
printインタフェース
class Print(metaclass=ABCMeta):
@abstractclassmethod
def print_weak(self):
pass
@abstractclassmethod
def print_strong(self):
pass
PrintBannerクラス
- Bannerクラスを継承する
- showWithParenメソッドおよびshowWithAsterメソッドを拡張する
PrintBanner
class PrintBanner(Banner, Print):
def __init__(self, string):
Banner.__init__(string)
def print_weak(self):
self.show_with_paren()
def print_strong(self):
self.show_with_aster()
Main
- PrintBannerインスタンスを作成し、文字列を表示するだけ
- Bannerクラスのメソッド「show_with_paren」「show_with_aster」がmainメソッドから隠蔽されている
Main
def main():
p = PrintBanner("Hello")
p.print_weak()
p.print_strong()
実行結果
実行結果
Air% python adapter_pattern.py
(Hello)
*Hello*
パターン2 委譲を使ったパターン
- PrintBannerクラスのフィールドにBannerインスタンスが含まれる
- PrintBannerクラスはprintWeakメソッドが呼ばれた時に、Bannerクラスに実際の処理を委譲する
- 具体的な処理はBannerに任せる
Printクラス
- 継承を利用するパターンではインタフェースで宣言しているが、委譲ではクラスとして宣言する
- PrintBannerクラスが継承する
コード全体
委譲を使ったパターン
from abc import ABCMeta, abstractclassmethod
class Banner():
def __init__(self, string):
self._string = string
def show_with_paren(self):
print("({})".format(self._string))
def show_with_aster(self):
print("*{}*".format(self._string))
class Print(metaclass=ABCMeta):
@abstractclassmethod
def print_weak(self):
pass
@abstractclassmethod
def print_strong(self):
pass
class PrintBanner(Print):
def __init__(self, string):
self._banner = Banner(string)
def print_weak(self):
self._banner.show_with_paren()
def print_strong(self):
self._banner.show_with_aster()
def main():
p = PrintBanner("Hello")
p.print_weak()
p.print_strong()
if __name__ == "__main__":
main()
所感
- すでに作られているプログラムや前バージョンのAPIを拡張する場合に利用できると考える
- 既存コードを変更せずに機能拡張できるところが大きい