Python基礎 オブジェクト指向12(Chain of Responsibility) 振る舞いに関するデザインパターン
| 登録日 | :2025/10/05 11:13 |
|---|---|
| カテゴリ | :Python基礎 |
Chain of Responsibility
クライアントからのリクエストを処理するオブジェクトを鎖のように繋げ、処理が可能なオブジェクトにリクエストを順番に渡していくパターン
- バケツリレーのようなイメージ
- リクエストが渡されたオブジェクト(ハンドラ)は自信で処理する必要があるかどうかを判断し、自分で対処できない場合は次のハンドラに渡す
構成要素
Handler
- 抽象クラスもしくはインターフェース
- クライアントからの要求を処理するAPIを定義
- 内部に別の処理を行うオブジェクトを保持
ConcreteHandler
- Handlerを継承(実装)するクラス
- Handlerで定義されたAPIを満たすように自身が担当する処理を実装する
Client
- Handlerにリクエストを送信する
オブジェクト指向的要素
「ポリモーフィズム」を利用したパターン
- オブジェクトのチェーンは全てHandler型であり、ConcreteHandlerクラスを意識する必要がない
- HandlerのAPIを使用することで、ConcreteHandlerの切り替えが可能になる
メリット・デメリット
メリット
- リクエスト処理の順序を制御できる
- リクエストの送信側と受信側の結びつきを弱くする
- 新しい処理クラスを容易に追加できる
デメリット
- 処理がたらい回しにされるので、パフォーマンスに影響が出る可能性がある
使い所
特定の順序で複数の処理を実行する必要がある場合
例)フォームの入力値バリデーション
Handlerの組み合わせと順序を実行時に変更したい場合
setterメソッドでnextをセットすることで、実行時に次の処理を決定できる
サンプルコード
入力された文字列のバリデーション
from __future__ import annotations
"""自身のクラスを戻り値に設定するため、annotationsが必要"""
import re
from abc import ABCMeta, abstractmethod
class ValidationHandler(metaclass=ABCMeta):
def __init__(self):
self.__next_handler = None
def set_handler(self, _handler: ValidationHandler):
self.__next_handler = _handler
return _handler
@abstractmethod
def _exec_validation(self, _input: str) -> bool:
pass
@abstractmethod
def _get_error_message(self):
pass
def validate(self, _input: str) -> bool:
result = self._exec_validation(_input)
if not result:
self._get_error_message()
return False
elif self.__next_handler:
return self.__next_handler.validate(_input)
else:
return True
class NotNullValidationHandler(ValidationHandler):
def _exec_validation(self, _input: str) -> bool:
result = False
if _input:
result = True
print(f"[INFO]: NotNullValidation: {result}")
return result
def _get_error_message(self):
print("[ERROR]: Input is Null.")
class AlphabetValidationHandler(ValidationHandler):
def _exec_validation(self, _input: str) -> bool:
reg = re.compile("^[a-zA-Z]+$")
result = bool(re.search(reg, _input))
print(f"[INFO]: AlphabetValidationHandler: {result}")
return result
def _get_error_message(self):
print("[ERROR]: Please input Alphabet only.")
MIN_LENGTH = 8
class MinLengthValidationHandler(ValidationHandler):
def _exec_validation(self, _input: str) -> bool:
result = (len(_input) >= MIN_LENGTH)
print(f"[INFO]: MinLengthValidationHandler: {result}")
return result
def _get_error_message(self):
print(f"[ERROR]: Please input character which size are more than {MIN_LENGTH}")
if __name__ == '__main__':
not_null_handler = NotNullValidationHandler()
alphabet_handler = AlphabetValidationHandler()
min_length_handler = MinLengthValidationHandler()
# not null -> alphabet -> min length
not_null_handler.set_handler(alphabet_handler).set_handler(min_length_handler)
result = not_null_handler.validate('')
if result:
print("passed")
print('')
result = not_null_handler.validate('1')
if result:
print("passed")
print('')
result = not_null_handler.validate('a')
if result:
print("passed")
print('--- success case ---')
result = not_null_handler.validate('aaaaaaaaaaa')
if result:
print("passed")