第28章:訪問者模式
訪問者模式
訪問者模式(visitor):表示一個作用於某對象結構中的各元素的操作。它使你可以在不改變各元素的類的前提下定義作用於這些元素的新操作。
Visitor
類:爲該對象結構中ConcreteElement
的每一個類聲明一個Visit
操作。
ConcreteVisitor1
和ConcreteVisitor2
類:具體訪問者,實現每個由Visitor
聲明的操作。每個操作實現算法的一部分,而該算法片斷乃是對應於結構中對象的類。
Element
類:定義一個Accept
操作,它以一個訪問者爲參數。
ConcreteElementA
和ConcreteElementB
類:具體元素,實現Accept
操作。
ObjectStructure
類:能枚舉它的元素,可以提供一個高層的接口以允許訪問者訪問它的元素。
客戶端代碼
訪問者模式適用於數據結構相對穩定的系統,它把數據結構和作用於結構上的操作之間的耦合解脫開,使得操作集合可以相對自由地
演化。
訪問者模式的目的是要把處理從數據結構分離出來。很多系統可以按照算法和數據結構分開,如果這樣的系統有比較穩定的數據結構,又有易於變化的算法的話,使用訪問者模式就是比較合適的,因爲訪問者模式使得算法操作的增加變得容易。反之,如果這樣的系統的數據結構對象易於變化,經常要有新的數據對象增加進來,就不適合使用訪問者模式。
訪問者模式的優點就是增加新的操作很容易,因爲增加新的操作就意味着增加一個新的訪問者。訪問者模式將有關的行爲集中到一個訪問者對象中。
訪問者的缺點也就是使增加新的數據結構變得困難了。
GoF
的一個作者曾說:“大多時候,你並不需要訪問者模式,但當一旦你需要訪問者模式時,那就是真的需要它了。”
訪問者模式示例
任務:男人和女人的區別
from abc import ABCMeta, abstractmethod
from typing import Text
class Action(metaclass=ABCMeta):
"""
狀態抽象(Visitor)類
"""
@abstractmethod
def get_man_conclusion(self, man: object) -> None:
"""
得到男人結論或反應
"""
pass
@abstractmethod
def get_woman_conclusion(self, woman: object) -> None:
"""
得到女人結論或反應
"""
pass
class Success(Action):
"""
成功(ConcreteVisitor)類
"""
def get_man_conclusion(self, man: object) -> None:
print("{}{}時,背後多半有一個偉大的女人。".format(str(man), str(self)))
def get_woman_conclusion(self, woman: object) -> None:
print("{}{}時,背後大多有一個不成功的男人。".format(str(woman), str(self)))
def __str__(self) -> Text:
return "成功"
class Failing(Action):
"""
失敗(ConcreteVisitor)類
"""
def get_man_conclusion(self, man: object) -> None:
print("{}{}時,悶頭喝酒,誰也不用勸。".format(str(man), str(self)))
def get_woman_conclusion(self, woman: object) -> None:
print("{}{}時,眼淚汪汪,誰也勸不了。".format(str(woman), str(self)))
def __str__(self) -> Text:
return "失敗"
class Amativeness(Action):
"""
戀愛(ConcreteVisitor)類
"""
def get_man_conclusion(self, man: object) -> None:
print("{}{}時,凡事不懂也要裝懂。".format(str(man), str(self)))
def get_woman_conclusion(self, woman: object) -> None:
print("{}{}時,遇事懂也裝作不懂。".format(str(woman), str(self)))
def __str__(self) -> Text:
return "戀愛"
class Person(metaclass=ABCMeta):
"""
人抽象(Element)類
"""
@abstractmethod
def accept(self, visitor: Action) -> None:
"""
接受
"""
pass
class Man(Person):
"""
男人(ConcreteElement)類
"""
def accept(self, visitor: Action) -> None:
visitor.get_man_conclusion(self)
def __str__(self) -> Text:
return "男人"
class Woman(Person):
"""
女人(ConcreteElement)類
"""
def accept(self, visitor: Action) -> None:
visitor.get_woman_conclusion(self)
def __str__(self) -> Text:
return "女人"
class ObjectStructure(object):
"""
對象結構(ObjectStructure)類
"""
def __init__(self) -> None:
self.__elements = []
def attach(self, element: Person) -> None:
self.__elements.append(element)
def detach(self, element: Person) -> None:
self.__elements.remove(element)
def display(self, visitor: Action) -> None:
for e in self.__elements:
e.accept(visitor)
# 客戶端代碼
if __name__ == "__main__":
o = ObjectStructure()
o.attach(Man())
o.attach(Woman())
# 成功時的反應
v1 = Success()
o.display(v1)
# 失敗時的反應
v2 = Failing()
o.display(v2)
# 戀愛時的反應
v3 = Amativeness()
o.display(v3)
男人成功時,背後多半有一個偉大的女人。
女人成功時,背後大多有一個不成功的男人。
男人失敗時,悶頭喝酒,誰也不用勸。
女人失敗時,眼淚汪汪,誰也勸不了。
男人戀愛時,凡事不懂也要裝懂。
女人戀愛時,遇事懂也裝作不懂。