デザインパターン(Design Pattern)#Adapter
設計を意識したコードが書けるようになる為に、デザインパターン修行しました。
他のDesign Patternもちょくちょく出していきます。
前置き
- 増補改訂版Java言語で学ぶデザインパターン入門をJavaからPythonにしてます。(Pythonは3.4.2)
- githubにコード置いてあります(まだ動かないものもある)
デザインパターンをどういう時に、何を、どう使うのかを理解することが一先ずの目標。
(Javaというか静的型付言語は初めてで、且つpython歴もそんなに長くないので、Pythonistaぽっくないところがあると思います。ご指摘ございましたらご教授ください。)
今回は、構造に関するパターンAdapter。
Adapterとは
Adapterパターンには以下の2種がある。
1. クラスによるAdapterパターン(継承を使ったもの)
2. インスタンスによるAdapterパターン(委譲を使ったもの)
2つのクラス間に変換構造を作り、別の用途に使えるように変換する。Apdaterは中間層の役割で、使う方と、使われる方は中身を知らなくても良い。要はクラスで返すのか、インスタンスで返すのかの違いかな。
概要
クラスによる継承Apapterパターンを使ったサンプルと委譲によるサンプルプログラムがあります。両者とも与えられた文字列を(文字列)や*文字列*のように表示します。
Bannerクラスには、文字列をカッコでくくって表示するshow_with_parenというメソッドと、文字列の前後に*印を付けて表示するshow_with_parenというメソッドが用意されています。Bannerクラスが既存のものだと仮定します。
Printインタフェースでは、文字列を弱く(カッコ付きで)表示するためのメソッドprint_weakと、文字列を強く表示するためのメソッドprint_strongが宣言されています。
アダプターの役割を担うのがPrinterBannerクラスです。このクラスは、提供されているBannerクラスを継承し、必要とされているPrinterインタフェースを実装する。これでPrinterBannerクラスはアダプターとしての機能を果たすことになります。
継承パターンのクラス図
Adapter 継承パターン
class Banner():
def __init__(self, string):
self.__string = string
def show_with_paren(self):
print('({0})').format(self.__string))
def show_with_aster(self):
print('({0})').format(self.__string))
from abc import ABCMeta, abstractmethod
class Printer(metaclass=ABCMeta):
@abstractmethod
def print_weak(self):
pass
@abstractmethod
def print_strong(self):
pass
from banner import Banner
class PrinterBanner(Banner)
def __init__(self, string):
super().__init__(string)
def print_weak(self):
self.show_with_paren()
def print_strong(self):
self.show_with_aster()
PrintBannerクラスがAdapterの役割をしています。
Bannerクラスを継承して、show_with_parenメソッドとshow_with_asterメソッドを継承します。
更に、要求されているPrinterインタフェースをしてprint_weakメソッドとprint_strongメソッドを実装してます。
from printer_banner import PrinterBanner
if __name__ == '__main__':
pb = PrinterBanner('Bye')
pb.print_weak()
pb.print_strong()
Printerインタフェースを使ってprint_weak()とprint_strong()で出力している。mainの方では、PrinterBannerクラスがどのような実装になってるか知らないので、mainクラスを変更せずともPrinterBannerクラスの実装を変えることができる。
Adapter 委譲パターン
委譲によるサンプルプログラムはMainとBannerは継承パターンと同じです。異なるのはPrintBannerクラスだけ。つまり、Bannerクラスを利用して、Printerクラスと同じメソッドを持つクラスを実現しようという。
PrinterBannerクラスは、bannerフィールドでBannerクラスのインスタンスを保持します。このインスタンスはPrinterBannerクラスのコンストラクタで生成します。そして、print_weak及び、print_strongメソッドでは、そのbannerフィールドを介してshow_with_paren, show_with_asterメソッドを呼び出します。
継承を使った方だと、自分のスーパークラスから継承したshow_with_paren, show_with_asterメソッドを呼び出しますが、委譲のパターンではフィールド経由で呼び出しています。
PrinterBannerクラスのprint_weakメソッドが呼ばれた時、自分で処理するのではなく、別のインスタンス(Bannerのインスタンス)のshow_with_parenメソッドにお任せしている。これが委譲になります。
委譲パターンのクラス図
from printer import Printer
from banner import Banner
class PrinterBanner(Printer):
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()
今度はPrinterクラスを継承して、まずBannerクラスのインスタンスを呼んでいる。
それで呼んだインスタンスに対してshow_with_parenメソッドとshow_with_asterメソッドを使ってprint_weakメソッドとprint_strongメソッドを実装している。
文言だけ変えてるけど、出力結果は一緒。
(Bye)
*Bye*
(Hello)
*Hello*
まとめ
Adapterパターンは、既存のクラスに一皮かぶせて必要とするクラスを作る。つまり、インタフェースとなる部分が間に入って、異なる二者間のズレを埋め合わせる。
バグが出たとしても、既存のクラスにはバグがないことがわかっているのでAdapter役のクラスを重点的に調べればよいことになり、プログラムのチェックがとても楽になるのと、既存のクラスの仕様だけがわかれば、新しいクラスを作ることができる。
参考
Author And Source
この問題について(デザインパターン(Design Pattern)#Adapter), 我々は、より多くの情報をここで見つけました https://qiita.com/nirperm/items/2b5c6f39beb70448e6c1著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .