pythonによるデザインパターン[Adapter]
# Intro
この文章は結城 浩さんの「Java言語で学ぶデザインパターン入門」を、pythonで実装してみたサンプルコードです。
筆者の環境は以下の通りです。Python 3.6.3
まだ修行中の身なので間違いがあると思いますがご了承ください。 今回は「Adapter」です。
# Summarise
本書のp16によると、 Adapterとは
「すでに提供されているもの」と「必要なもの」の間の「ずれ」を埋める
とあります。似ているけれど、異なるAPIがあったときにその間に中間クラスを作成し、違いを埋めるような感じです。Adapterには2種類あり以下のように分類されます。
- クラス(継承)によるAdapter
- インスタンス(委譲)によるAdapter
大きく違いはないのですが、今回はどちらも説明します。
# Practice
## Specification
class Banner
があり、このクラスは以下のメソッドを持ちます。
- 文字を()を閉じて表示する
def show_with_paren
例)(Hello)
- 文字を*で閉じて表示する
def show_witH_weak
例)*Hello*
また、以下の抽象メソッドを持つ、抽象クラス class Print
があります。
- 文字を()を閉じて表示する
def print_weak
- 文字を*で閉じて表示する
def print_strong
class Banner
とclass Print
を両方とも満たすclass PrintBanner
を作成してください。その後、main関数から以下のようにclass PrintBanner
のインスタンスを呼び出し、文字を()を閉じて表示する def print_weak
と文字を*で閉じて表示する def print_strong
を実行してください。
python3 adapter.py (Hello)
*Hello*
## Explanation
上で述べたclass PrintBanner
はclass Banner
とclass Print
の間をとりもつAdapterの役割を持ちます。最初に述べたように、2つの方法でclass PrintBanner
を実装しましょう。
1. クラス(継承)によるAdapter
pythonは言語仕様として多重継承をサポートしているので、class Banner
とclass Print
を多重継承しましょう。
まずclass PrintBanner
を生成するときに、親クラスのclass Banner
を呼び出します。
def __init__(self, string):
super().__init__(string)
そして、class Print
のdef print_weak
と def print_strong
の具体的な実装は、class Banner
を継承しているので self
(class Banner
自身)からdef show_with_paren
と def show_witH_weak
を呼び出しましょう。
2. インスタンス(委譲)によるAdapter
委譲(delegation)とはクラスにFieldを置いてそのFieldに別のインスタンスを代入して、クラス間を結びつけることです。Bridgeでも同じ考え方が出てきたのでよかったら確認してみてください。
具体的な例を見ていきましょう。先ほどの多重継承をやめ、抽象クラスclass Print
だけの単一継承とします。その上でclass PrintBanner
を生成するときに、class Banner
のインスタンスを__baner
というFieldに代入します。このようにして、class PrintBanner
とclass Banner
は__baner
というFieldによって結び付けられています。
def __init__(self, string):
self.__banner = Banner(string)
そして、class Print
のdef print_weak
と def print_strong
の具体的な実装は、_baner
というFieldからdef show_with_paren
と def show_witH_weak
を呼び出しましょう。
## Sample Code
1. クラス(継承)によるAdapter
2. インスタンス(委譲)によるAdapter
# Conclusion
Adapterでは継承・委譲によって、2つのAPI間の変換を行いました。この継承・委譲といったテクニックはデザインパターンに頻出なので覚えましょう。
それではどのような時に継承を使って、どんな時に委譲を使えばいいのでしょうか?私もまだちゃんとは理解していませんが、継承はclass同士の強い結びつきで、委譲はそれに比べると緩やかな結びつきだと思います。
例えば、抽象クラスを継承すると必ず抽象メソッドを実装しないとエラーが出ますが、委譲なら別にエラーは出ません。よって2つのclassが強固な結びつきなら継承を使い、緩やかな結びつきなら委譲を使えばいいと思います。ですが、これは言語仕様にもよると思うので、ベストアンサーは言語によりけりかもしれません…😔😔😔
Adapterはバージョンアップする時に、古いAPIと新しいAPIをつなぐ役割など、実際によく出てくるので覚えておきたいデザインパターンですね。
# ref
- 「増補改訂版 Java言語で学ぶデザインパターン入門」 結城浩(著)第11版