「オブジェクト同士のやりとりを仲介者(Mediator)により簡素化する」パターンです。
ここでは、よくあるHTMLのフォームのバックエンド側のシステムを作ります。
システムの仕様は以下です。
TextForm
クラス、Button
クラスを作成し、やり取りをします。def main():
textarea_id = TextArea("ID")
textarea_pw = TextArea("PW")
button = Button("Login")
# buttonはMediatorに作用しても何もおきない
mediator = Mediator(textarea_id, textarea_pw, button)
# IDを入力
textarea_id.change_text("hoge")
# まだアクティブでないため、ボタンをおしてもなにもおきない
button.click() # (Ignored as button is disabled...)
# PWを入力(ここでアクティブになる)
textarea_pw.change_text("huga") # (Active Login Button)
button.click() # (ID and PW is confirmed)
# Mediator
class Mediator:
def __init__(self, obj_textarea_id, obj_textarea_pw, obj_button):
self.obj_button = obj_button
self.obj_textarea_id = obj_textarea_id
self.obj_textarea_pw = obj_textarea_pw
obj_button.mediator = self
obj_textarea_id.mediator = self
obj_textarea_pw.mediator = self
# consultation()
def on_change(self, component):
if component.name == "ID" or component.name == "PW":
self.update_ui()
elif component.name == "Login":
self.confirm_id_pw()
def update_ui(self):
if bool(self.obj_textarea_id.text) and bool(self.obj_textarea_pw.text):
print("(Active login button)")
self.obj_button.active = True
def confirm_id_pw(self):
if self.obj_textarea_id.text == "hoge" and self.obj_textarea_pw.text == "huga":
print("(ID and PW is confirmed)")
else:
print("(ID or PW is incorrect)")
# Colleague
class Mediated:
def __init__(self):
self.mediator = None
# advice
def on_change(self):
if self.mediator is not None:
self.mediator.on_change(self)
# ConcreteColleague
class Button(Mediated):
def __init__(self, name=""):
super().__init__()
self.active = False
self.name = name
def click(self):
if self.active:
self.on_change()
else:
print("(Ignored as button is disabled...)")
# ConcreteColleague
class TextArea(Mediated):
def __init__(self, name=""):
super().__init__()
self.name = name
self.text = ""
def change_text(self, text):
self.text = text
self.on_change()
if __name__ == "__main__":
main()
なお、main
文のmediatorをコメントアウトしても、エラーは起きないものの、ボタンがアクティブになりません。
# Mediator
class Mediator:
...
# consultation()
def on_change(self, component):
if component.name == "ID" or component.name == "PW":
self.update_ui()
elif component.name == "Login":
self.confirm_id_pw()
Mediator側は、on_change
関数が呼ばれたら、呼び出し元のobjectに従って、いろいろします。
Mediator側は、Mediated(= Colleague)側のすべてを知っている必要があります。
そのため、Mediatorクラスはどうしても複雑なものとなり、使い捨てに近いものとなる可能性は高いです。
# Colleague
class Mediated:
def __init__(self):
self.mediator = None
# advice
def on_change(self):
if self.mediator is not None:
self.mediator.on_change(self)
...
# ConcreteColleague
class TextArea(Mediated):
def __init__(self, name=""):
super().__init__()
self.name = name
self.text = ""
def change_text(self, text):
self.text = text
self.on_change()
仲介されるクラスは、全てMediated
を継承する必要があります。
子クラスで、self.on_change()
(親クラスで定義した関数)を呼ぶことでMediatorに変化を通知することができます。
特になし
実践Python3にはコルーチンを用いた書き方もあるが、省略しました。