オブジェクト間の責務の分配やコミュニケーションの方法に関するパターン群。
Observer¶
状態が変わったら通知(イベントリスナー)
class Subject:
def __init__(self):
self.observers = []
def attach(self, observer):
self.observers.append(observer)
def notify(self, msg):
for ob in self.observers:
ob.update(msg)
class Observer:
def update(self, msg):
print("Got:", msg)
s = Subject()
s.attach(Observer())
s.notify("Update available")Got: Update available
例:logging
logging パッケージでは addHandler() で self.handlers にハンドラーを追加し、ログ出力時に for hdlr in self.handlers で扱っていく
import logging
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
# 標準出力のハンドラーを追加
ch = logging.StreamHandler()
logger.addHandler(ch)
logger.info('hello world')Lib/logging/init.py#L1734-L1737
Strategy¶
アルゴリズムを切り替えられるようにする
class Strategy:
def execute(self, data):
pass
class Add(Strategy):
def execute(self, data):
return sum(data)
class Multiply(Strategy):
def execute(self, data):
result = 1
for x in data: result *= x
return result
def run(strategy: Strategy, data):
return strategy.execute(data)
print(run(Add(), [1, 2, 3]))
print(run(Multiply(), [1, 2, 3]))6
6
State¶
オブジェクトの内部状態に応じて振る舞いを切り替えるパターン。if/switch による状態分岐の乱立を、状態ごとのクラスに置き換える。
Strategyと構造は似ているが、Stateはオブジェクト自身が状態遷移を管理する点が異なる。
class State:
def handle(self, order): raise NotImplementedError
class PendingState(State):
def handle(self, order):
print("支払い待ち → 発送準備へ")
order.state = ShippedState()
class ShippedState(State):
def handle(self, order):
print("発送済み → これ以上遷移しない")
class Order:
def __init__(self):
self.state: State = PendingState()
def proceed(self):
self.state.handle(self)
order = Order()
order.proceed()Command¶
「実行してほしい操作」をオブジェクトとしてカプセル化するパターン。呼び出し元(Invoker)と実行対象(Receiver)を分離でき、 コマンドのキューイング・ログ記録・Undo/Redoの実装が容易になる。
class Light:
def on(self): print("light on")
def off(self): print("light off")
class Command:
def execute(self): raise NotImplementedError
class LightOnCommand(Command):
def __init__(self, light):
self.light = light
def execute(self):
self.light.on()
class RemoteControl:
def __init__(self):
self.history = []
def submit(self, command: Command):
command.execute()
self.history.append(command)
remote = RemoteControl()
remote.submit(LightOnCommand(Light()))Iterator¶
集約オブジェクトの内部表現を公開せずに、要素へ順次アクセスする手段を提供するパターン。Pythonでは __iter__ /
__next__ プロトコルとしてすでに言語仕様に組み込まれており、独自コンテナ型を作るときに自然と使うことになる。
class Range3:
def __init__(self, n):
self.n = n
def __iter__(self):
self.i = 0
return self
def __next__(self):
if self.i >= self.n:
raise StopIteration
self.i += 1
return self.i - 1
for x in Range3(3):
print(x)