Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

振る舞いに関するパターン(Behavioral Patterns)

オブジェクト間の責務の分配やコミュニケーションの方法に関するパターン群。

Observer

状態が変わったら通知(イベントリスナー)

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

アルゴリズムを切り替えられるようにする

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)