- Pythonとデザインパターンの学習記録。今回はFactory Methodパターンについてメモする。
Factory Methodパターン とは
- インスタンスの生成方法を親クラスで定義し、具体的な処理を子クラスで行う、デザインパターンの一つ。
- 実際のインスタンス生成を子クラスに行わせることで、生成するインスタンスを柔軟に選択できるようにする。
- 生成するインスタンスごとにファクトリ(下記Creator)を用意する。
クラス図と用語
- 抽象クラス
- Creator:インスタンス生成クラス
- Product:生成対象オブジェクト
- 具象クラス:抽象クラスに対応するCreatorとProduct
サンプルプログラム
ディレクトリ構成
Project
│ app.py
L_ api
│ __init__.py
│
├─views
│ sample.py
│ __init__.py
│
L_ factorymethod
│ factory.py
L_ __init__.py
│
L_ generatorfactory
L_ one_char_id_generator_factory.py
L_ random_id_generator_factory.py
L_ __init__.py
実装
-
app.py
from api import app if __name__ == '__main__': app.run()
-
api/__init__.py
from flask import Flask from .views.sample import sample_router def create_app(): app = Flask(__name__) app.register_blueprint(sample_router, url_prefix='/api') return app app = create_app()
-
api/views/sample.py
- APIコントローラ
-
クエリパラメータの有無でID生成方法を切り替える。
from flask import Flask, Blueprint, request import json from .factorymethod.generatorfactory.one_char_id_generator_factory import OneCharIDGenratorFactory from .factorymethod.generatorfactory.random_id_generator_factory import RandomIDGenratorFactory # Routing Settings sample_router = Blueprint('sample_router', __name__) app = Flask(__name__) def generateID(factoryObject, length): generator = factoryObject.create(length) return generator.generate() @sample_router.route("/sample", methods=['GET']) def get(): query = request.args.get('q') id = "" if query is not None: id = generateID(OneCharIDGenratorFactory(), 5) else: id = generateID(RandomIDGenratorFactory(), 5) res_body = { "id": id } return json.loads(json.dumps(res_body))
-
api/views/factorymethod/factory.py
- 抽象Creator、Product 定義
from abc import ABCMeta, abstractmethod # Creator class Factory(metaclass=ABCMeta): def create(self, length): p = self.createGenerator(length) return p @abstractmethod def createGenerator(self, length): pass # Product class Generator(metaclass=ABCMeta): @abstractmethod def generate(self, length): pass
-
api/views/factorymethod/one_char_id_generator_factory.py
- 具象Creator/Product
- 文字種1のランダムIDを生成
from api.views.factorymethod.factory import Factory, Generator import random class OneCharIDGenratorFactory(Factory): def __init__(self): self.length = 0 def createGenerator(self, length): return OneCharIDGenerator(length) class OneCharIDGenerator(Generator): def __init__(self, length): self.length = length print("長さ:{0} の1文字種 IDを生成します。".format(self.length)) def generate(self): chars = '0123456789abcdefghijklmnopqrstuvwxyz' v = random.choice(chars) id = ''.join([v for _ in range(self.length)]) print("ID:{0} を生成しました。".format(id)) return id
-
api/views/factorymethod/random_id_generator_factory.py
- 具象Creator/Product
- 複数文字種のランダムIDを生成
from api.views.factorymethod.factory import Factory, Generator import random class RandomIDGenratorFactory(Factory): def __init__(self): self.length = 0 def createGenerator(self, length): return RandomIDGenerator(length) class RandomIDGenerator(Generator): def __init__(self, length): self.length = length print("長さ:{0} のランダムIDを生成します。".format(self.length)) def generate(self): chars = '0123456789abcdefghijklmnopqrstuvwxyz' id = ''.join([random.choice(chars) for _ in range(self.length)]) print("ID:{0} を生成しました。".format(id)) return id
動作確認
-
複数文字種のランダムID生成(クエリパラメータ指定なし)
-
リクエスト
GET /api/sample HTTP/1.1 Host: localhost:5000
-
レスポンス
{ "id": "1arh3j2jba8x2fix" }
-
-
1文字種のランダムID生成(クエリパラメータ指定あり)
-
リクエスト
GET /api/sample?q=test HTTP/1.1 Host: localhost:5000
-
レスポンス
{ "id": "nnnnn" }
-