Python

Python デザインパターンを学ぶ Mediatorパターン

概要

オブジェクト間の多対多の関係を構築・管理する必要がある場合、Mediatorパターンは、これらの関係を維持する仲介オブジェクトを作成すること解決策を提供する。関連する全てのオブジェクトはMediatorへのポインタを保持し、Mediatorは前述の全てのオブジェクトへのポインタを保持する。これにより、お互いを知らないオブジェクト間の通信が可能になる(疎結合にする)。

次の例では、このパターンを使用して、複雑な内部関係を持つノードのネットワークを管理する。

このネットワークには、マスター・ノード、ローカル・マスター・ノード、ジェネラル・ノードの3種類のノードがある。各ノードには、「アクティブ」な状態をトグルする、アクティブと非アクティブのスイッチ(メソッド)がある。マスターノードをトグルすると、ネットワーク全体がアクティブになったり、非アクティブになったりする。 ローカル・マスター・ノード をトグルすると、そのローカルグループ内のすべてのノードに対して同じことを行う(グローバルマスターノードは除く)。ジェネラルノードをトグルすると、そのノードの状態にのみ影響を与える。最後に、すべてのノードは1つのローカルグループにしか属さない。

実装例

NetworkMediatorクラスが、名前の通りMediatorパターンを適用されたもの。すべてのノード間の関係を維持する役割を担う。全てのノードの「アクティブ」な状態を管理し、前述のdocstringで定義された動作ルールに準拠する。

register_member関数は、ノードがネットワークに追加されると、Mediator は(このメソッドを呼び出した)ノード自身によってそのことを認識する。つまり、ノードとMediatorの両方がお互いを認識している。

誰かがノードを活性化したり非活性化したりすると、そのノードからこのメソッド(toggle関数)が呼び出される。ノードが自身の状態やネットワーク上の他の影響を受けるノードの状態を管理するのではなく、Mediatorがすべての処理を行う。これにより、ノード間の疎結合を実現する。

Nodeクラスのactivate関数/deactivate関数は、そのノードとその影響を受ける全てのノードを有効化/無効化にするよう Mediatorへ通知する。ノードは、他のどのノードが起動されるかについては何も知らない。

class NetworkMediator:
    def __init__(self):
        self._nodes = []

    def register_member(self, member):

        self._nodes.append(member)

    def toggle(self, source, activate):

        if source.type == 'master':
            self._toggle_all(activate)
        elif source.type == 'local_master':
            self._toggle_local(local_group=source.local_group,
                               activate=activate)
        else:
            print("{} the {} node.".format(
                'Activating' if activate else 'Deactivating', source.name))
            source.active = activate

    def _toggle_all(self, activate):

        print("{} all nodes".format(
            'Activating' if activate else 'Deactivating'))
        for node in self._nodes:
            node.active = activate

    def _toggle_local(self, local_group, activate):
        print("{} all nodes in the {} local group.".format(
            'Activating' if activate else 'Deactivating', local_group))
        for node in self._nodes:
            if node.local_group == local_group and node.type != 'master':
                node.active = activate

    def print_network_status(self):
        for node in self._nodes:
            print(str(node.name), str(node.active))


class Node:

    def __init__(self, mediator, name, n_type, local_group):

        self.mediator = mediator
        self.name = name
        self.type = n_type
        self.local_group = local_group
        self.mediator.register_member(self)
        self.active = False

    def activate(self):
        self.mediator.toggle(source=self, activate=True)

    def deactivate(self):
        self.mediator.toggle(source=self, activate=False)


if __name__ == '__main__':

    mediator = NetworkMediator()
    master_node = Node(mediator, 'root', 'master', 'global')

    group1_master = Node(mediator, 'group1_root', 'local_master', 'G1')
    group1_node_a = Node(mediator, 'group1_a', 'general', 'G1')
    group1_node_b = Node(mediator, 'group1_b', 'general', 'G1')

    group2_master = Node(mediator, 'group2_root', 'local_master', 'G2')
    group2_node_a = Node(mediator, 'group2_a', 'general', 'G2')
    group2_node_b = Node(mediator, 'group2_b', 'general', 'G2')

    master_node.activate()
    group1_master.deactivate()
    group1_node_b.activate()

    mediator.print_network_status()