pythonによるデザインパターン[Adapter]

# Intro

この文章は結城 浩さんの「Java言語で学ぶデザインパターン入門」を、pythonで実装してみたサンプルコードです。

筆者の環境は以下の通りです。Python 3.6.3

まだ修行中の身なので間違いがあると思いますがご了承ください。 今回は「Adapter」です。

# Summarise

本書のp16によると、 Adapterとは

「すでに提供されているもの」と「必要なもの」の間の「ずれ」を埋める

とあります。似ているけれど、異なるAPIがあったときにその間に中間クラスを作成し、違いを埋めるような感じです。Adapterには2種類あり以下のように分類されます。

  1. クラス(継承)によるAdapter
  2. インスタンス(委譲)によるAdapter

大きく違いはないのですが、今回はどちらも説明します。

# Practice

## Specification

class Banner があり、このクラスは以下のメソッドを持ちます。

  • 文字を()を閉じて表示する def show_with_paren
    例) (Hello)
  • 文字を*で閉じて表示する def show_witH_weak
    例) *Hello*

また、以下の抽象メソッドを持つ、抽象クラス class Print があります。

  • 文字を()を閉じて表示する def print_weak
  • 文字を*で閉じて表示する def print_strong

class Bannerclass Print を両方とも満たすclass PrintBanner を作成してください。その後、main関数から以下のようにclass PrintBanner のインスタンスを呼び出し、文字を()を閉じて表示する def print_weak と文字を*で閉じて表示する def print_strong を実行してください。

python3 adapter.py   (Hello)
*Hello*

## Explanation

上で述べたclass PrintBannerclass Bannerclass Print の間をとりもつAdapterの役割を持ちます。最初に述べたように、2つの方法でclass PrintBanner を実装しましょう。

1. クラス(継承)によるAdapter

pythonは言語仕様として多重継承をサポートしているので、class Bannerclass Printを多重継承しましょう。

まずclass PrintBanner を生成するときに、親クラスのclass Banner を呼び出します。

def __init__(self, string):
super().__init__(string)

そして、class Printdef print_weakdef print_strong の具体的な実装は、class Banner継承しているので self (class Banner自身)からdef show_with_parendef show_witH_weak を呼び出しましょう。

2. インスタンス(委譲)によるAdapter

委譲(delegation)とはクラスにFieldを置いてそのFieldに別のインスタンスを代入して、クラス間を結びつけることです。Bridgeでも同じ考え方が出てきたのでよかったら確認してみてください。

具体的な例を見ていきましょう。先ほどの多重継承をやめ、抽象クラスclass Print だけの単一継承とします。その上でclass PrintBanner を生成するときに、class Banner のインスタンスを__banerというFieldに代入します。このようにして、class PrintBannerclass Banner__banerというFieldによって結び付けられています。

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

そして、class Printdef print_weakdef print_strong の具体的な実装は、_banerというFieldからdef show_with_parendef show_witH_weak を呼び出しましょう。

## Sample Code

1. クラス(継承)によるAdapter

2. インスタンス(委譲)によるAdapter

# Conclusion

Adapterでは継承・委譲によって、2つのAPI間の変換を行いました。この継承・委譲といったテクニックはデザインパターンに頻出なので覚えましょう。

それではどのような時に継承を使って、どんな時に委譲を使えばいいのでしょうか?私もまだちゃんとは理解していませんが、継承はclass同士の強い結びつきで、委譲はそれに比べると緩やかな結びつきだと思います。

例えば、抽象クラスを継承すると必ず抽象メソッドを実装しないとエラーが出ますが、委譲なら別にエラーは出ません。よって2つのclassが強固な結びつきなら継承を使い、緩やかな結びつきなら委譲を使えばいいと思います。ですが、これは言語仕様にもよると思うので、ベストアンサーは言語によりけりかもしれません…😔😔😔

Adapterはバージョンアップする時に、古いAPIと新しいAPIをつなぐ役割など、実際によく出てくるので覚えておきたいデザインパターンですね。

# ref

--

--