💡

Prototypeパターンを学ぶ【Python】

2022/02/06に公開

一言で言うと

生成済みのインスタンスから別のインスタンスを複製する。クラス名を指定せずにインスタンスを作りたい場合に使用できる。

コードサンプル

ディレクトリ構造
prototype
├── framework
│   ├── manager.py
│   └── product.py
├── main.py
├── message_box.py
└── under_line_pen.py
main.py
from framework.product import Product
from framework.manager import Manager
from message_box import MessageBox
from under_line_pen import UnderLinePen


def main():
    manager: Manager = Manager()
    upen: UnderLinePen = UnderLinePen('~')
    mbox: MessageBox = MessageBox('*')
    sbox: MessageBox = MessageBox('/')
    manager.register('strong message', upen)
    manager.register('warning box', mbox)
    manager.register('slash box', sbox)

    p1: Product = manager.create('strong message')
    p1.use('Hello, world.')
    p2: Product = manager.create('warning box')
    p2.use('Hello, world.')
    p3: Product = manager.create('slash box')
    p3.use('Hello, world.')


if __name__ == '__main__':
    main()
manager.py
from .product import Product


class Manager():
    __showcase: dict = {}

    def register(self, name: str, proto: Product) -> None:
        self.__showcase[name] = proto

    def create(self, protoname: str) -> Product:
        p: Product = self.__showcase.get(protoname)
        return p.createClone()
pruduct.py
from __future__ import annotations  # 自分自身のクラスを返せるようにする
from abc import ABCMeta, abstractmethod


class Product(metaclass=ABCMeta):
    @abstractmethod
    def use(s: str) -> None:
        pass

    @abstractmethod
    def createClone() -> Product:
        pass
message_box.py
from framework.product import Product
from functools import reduce
from operator import add
from unicodedata import east_asian_width
import copy


class MessageBox(Product):
    def __init__(self, decochar: str) -> None:
        self.decochar: str = decochar

    def use(self, s: str) -> None:
        length: int = reduce(
            # 全角2文字、半角1文字とする
            add, [2 if east_asian_width(ch) in 'FWA' else 1 for ch in s]
        )

        for _ in range(length + 4):
            print(self.decochar, end='')
        print('')
        print(f'{self.decochar} {s} {self.decochar}')
        for _ in range(length + 4):
            print(self.decochar, end='')
        print('')

    def createClone(self) -> Product:
        return copy.deepcopy(self)
under_line_pen.py
from framework.product import Product
from functools import reduce
from operator import add
from unicodedata import east_asian_width
import copy


class UnderLinePen(Product):
    def __init__(self, ulchar: str) -> None:
        self.ulchar: str = ulchar

    def use(self, s: str) -> None:
        length: int = reduce(
            # 全角2文字、半角1文字とする
            add, [2 if east_asian_width(ch) in 'FWA' else 1 for ch in s]
        )

        print(f'"{s}"')
        print(self.ulchar, end='')
        for _ in range(length):
            print(self.ulchar, end='')
        print('')

    def createClone(self) -> Product:
        return copy.deepcopy(self)

参考文献

実践python3
増補改訂版Java言語で学ぶデザインパターン入門

Discussion