Pythonで学ぶデザインパターン入門Prototypeパターン
結城先生の Java言語で学ぶデザインパターン入門
のコードを Python に書き直していくシリーズ第6段です。
Prototypeパターンとは
今回もインスタンス生成に関するパターンです。
ざっくり説明すると、インスタンスの雛形をどこかに保持しておき、それを元に新しいインスタンスを作成するパターンですね。
コピーのような形で作成するのがこのデザインパターンの特徴です。
ソースコード
コードの概要
文字列を渡すと、特定の装飾をした文字列が出力されるといったコードになります。
たとえば、 Hello
と渡したら、 *Hello*
のように装飾されるといったコードです。
例の *
のような装飾の文字が可変になる仕組みになっております。
今回は Manager
というクラスで、 Product
というクラスを継承したインスタンスをcloneしていきます。
つまり、 Manager
にインスタンスを保持しておけば好きな時にcloneできるといった仕組みです。
ソースコード
Product
# coding: utf-8 from abc import ABCMeta, abstractmethod class Product(metaclass=ABCMeta): @abstractmethod def use(self, s: str): pass @abstractmethod def create_clone(self): pass
このデザインパターンで利用する、cloneするインスタンスの抽象クラスです。
後術の Manager
クラスで create_clone
メソッドを呼び出して複製します。
Manager
# coding: utf-8 from prototype.framework.product import Product class Manager(object): def __init__(self): self.__showcase = {} def register(self, name: str, proto: Product): self.__showcase[name] = proto def create(self, protoname: str) -> Product: p = self.__showcase.get(protoname) return p.create_clone()
具体的にインスタンスを複製するクラスです。
登録したら、そのインスタンスの複製を作成できるようになります。
MassageBox (Productを継承)
# coding: utf-8 import copy from prototype.framework.product import Product class MessageBox(Product): def __init__(self, decochar: str): if len(decochar) > 1: raise TypeError('文字は一文字') self.__decochar = decochar def use(self, s: str): length = len(s.encode('utf-8')) for i in range(length + 4): print(self.__decochar, end='') print('') print('%s %s %s' % (self.__decochar, s , self.__decochar)) for i in range(length + 4): print(self.__decochar, end='') print('') def create_clone(self) -> Product: return copy.copy(self)
複製するためのインスタンスです。具体的には
*************** * warning box * ***************
のような形で文字列を4方から取り囲む形に出力されます。
UnderlinePen (Productを継承)
# coding: utf-8 import copy from prototype.framework.product import Product class UnderlinePen(Product): def __init__(self, ulchar): if len(ulchar) > 1: raise TypeError('文字は一文字') self.__ulchar = ulchar def use(self, s: str): length = len(s.encode('utf-8')) print('%s %s %s' % (self.__ulchar, s, self.__ulchar)) print(' ', end='') for i in range(length): print(self.__ulchar, end='') print('') def create_clone(self) -> Product: return copy.copy(self)
複製するためのインスタンス2です。具体的には
~ Hello World ~ ~~~~~~~~~~~
のように下線のような形で文字列を装飾します。
実行ファイル
# coding: utf-8 from prototype.framework.manager import Manager from prototype.message_box import MessageBox from prototype.underline_pen import UnderlinePen if __name__ == '__main__': manager = Manager() upen = UnderlinePen('~') mbox = MessageBox('*') sbox = MessageBox('/') manager.register('strong message', upen) manager.register('warning box', mbox) manager.register('slash box', sbox) p1 = manager.create('strong message') p1.use('Hello World') p2 = manager.create('warning box') p2.use('warning box') p3 = manager.create('slash box') p3.use('Hello World')
実行結果
~ Hello World ~ ~~~~~~~~~~~ *************** * warning box * *************** /////////////// / Hello World / ///////////////
実際どう便利か
このデザインパターンは使い所が非常に難しいです。
インスタンスを鬼のように作成して、同じ動作でインスタンスを沢山作成する場合は非常に使えるんではないでしょうか。
また、インスタンスを複製したいけど、マニュアル動作などから生成してるので複製が難しいといった場合も有用ですね。