- Pythonとデザインパターンの学習記録。今回はStrategyパターンについてメモする。
Strategy パターンとは
- 「戦略」(アルゴリズムなど)の切り替えや追加を簡単に行うためのデザインパターン。
- 戦略処理を別クラスとして作成することで、戦略を変更したい場合に、利用する戦略クラスを変更するという方法で対応する。
- メソッド中にアルゴリズムをべた書きするよりも柔軟でメンテナンスしやすい設計となる。
クラス図と用語
- Strategy:特定の処理を抽象化したクラス(抽象戦略)
- ConcreteStrategy : 具体的な処理を行うクラス(具体戦略)
- Context:Strategyの利用者
サンプルプログラム
- ID生成処理を行うAPIに適用する。
- クエリパラメータの有無でID生成用Strategyを切り替える。
ディレクトリ構成
Project
│ app.py
│
│
L_ api
│ __init__.py
│
├─views
│ sample.py
│ __init__.py
│
L_ strategy
L_ IDgenerator.py
L_ IDStrategy.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コントローラ
from flask import Flask, Blueprint, request import json from .strategy.IDStrategy import IDStrategy from .strategy.IDStrategy import FixedIDStrategy, RandomIDStrategy from .strategy.IDgenerator import IDgenerator # Routing Settings sample_router = Blueprint('sample_router', __name__) app = Flask(__name__) @sample_router.route("/sample", methods=['GET']) def get(): query = request.args.get('q') id = "" # クエリパラメータ未指定の場合、固定のIDを取得する if query is not None: generator = IDgenerator(FixedIDStrategy()) id = generator.generateID() # クエリパラメータ指定ありの場合、ランダムのIDを取得する else: generator = IDgenerator(RandomIDStrategy()) id = generator.generateID() res_body = { "id": id } return json.loads(json.dumps(res_body))
-
api/views/strategy/IDStrategy.py
- Strategy:抽象、具体戦略(ランダム、固定ID生成)定義
import random # ID生成処理を抽象化したクラス(抽象戦略 Strategy) class IDStrategy: def generateID(self): raise 'Abstract Method Called' # ランダム生成したIDを返却するクラス(具体戦略 ConcreteStrategy) class RandomIDStrategy(IDStrategy): def generateID(self): chars = '0123456789abcdefghijklmnopqrstuvwxyz' return ''.join([random.choice(chars) for _ in range(16)]) # 固定IDを返却するクラス(具体戦略 ConcreteStrategy) class FixedIDStrategy(IDStrategy): def generateID(self): return '0123abcd4567efgh'
-
api/views/strategy/IDgenerator.py
- Context:ID生成Strategyを呼び出す。
# コンテキスト(Context):ストラテジーの利用者 class IDgenerator: def __init__(self, IDStrategy): self.IDStrategy = IDStrategy def generateID(self): return self.IDStrategy.generateID()
動作確認
-
ランダムID生成戦略の呼び出し(クエリパラメータ指定なし)
-
リクエスト
GET /api/sample HTTP/1.1 Host: localhost:5000
-
レスポンス
{ "id": "1arh3j2jba8x2fix" }
-
-
固定ID生成戦略の呼び出し(クエリパラメータ指定あり)
-
リクエスト
GET /api/sample?q=test HTTP/1.1 Host: localhost:5000
-
レスポンス
{ "id": "0123abcd4567efgh" }
-