訪問者模式
訪問者模式,是行為型設計模式之一。訪問者模式是一種將資料操作與資料結構分離的設計模式,它可以算是 23 中設計模式中最複雜的一個,但它的使用頻率並不是很高,大多數情況下,你並不需要使用訪問者模式,但是當你一旦需要使用它時,那你就是需要使用它了。 訪問者模式的基本想法是,軟體系統中擁有一個由許多物件構成的、比較穩定的物件結構,這些物件的類都擁有一個 accept 方法用來接受訪問者物件的訪問。訪問者是一個介面,它擁有一個 visit 方法,這個方法對訪問到的物件結構中不同型別的元素做出不同的處理。在物件結構的一次訪問過程中,我們遍歷整個物件結構,對每一個元素都實施 accept 方法,在每一個元素的 accept 方法中會呼叫訪問者的 visit 方法,從而使訪問者得以處理物件結構的每一個元素,我們可以針對物件結構設計不同的訪問者類來完成不同的操作,達到區別對待的效果。
定義及使用場景
定義: 封裝一些作用於某種資料結構中的各元素的操作,它可以在不改變這個資料結構的前提下定義作用於這些元素的新的操作。 可以對定義這麼理解:有這麼一個操作,它是作用於一些元素之上的,而這些元素屬於某一個物件結構。同時這個操作是在不改變各元素類的前提下,在這個前提下定義新操作是訪問者模式精髓中的精髓。
使用場景: (1)物件結構比較穩定,但經常需要在此物件結構上定義新的操作。 (2)需要對一個物件結構中的物件進行很多不同的且不相關的操作,而需要避免這些操作“汙染”這些物件的類,也不希望在增加新操作時修改這些類。
UML圖
程式碼示例
#encoding=utf-8
#
#by panda
#訪問模式
def printInfo(info):
print unicode(info, 'utf-8').encode('gbk')
#基本資料結構:
class Person():
def Accept(self, visitor):
pass
class Man(Person):
type = '男人'
def Accept(self, visitor):
visitor.GetManConclusion(self)
class Woman(Person):
type = '女人'
def Accept(self, visitor):
visitor.GetWomanConclusion(self)
#基於資料結構的操作
class Action():
def GetManConclusion(self, person):
pass
def GetWomanConclusion(self, person):
pass
class Success(Action):
type = '成功'
def GetManConclusion(self, person):
printInfo('%s %s時,背後多半有一個偉大的女人' %(person.type, self.type))
def GetWomanConclusion(self, person):
printInfo('%s %s時,背後大多有一個不成功的男人' %(person.type, self.type))
class Failing(Action):
type = '失敗'
def GetManConclusion(self, person):
printInfo('%s %s時,悶頭喝酒,誰也不用勸' %(person.type, self.type))
def GetWomanConclusion(self, person):
printInfo('%s %s時,眼淚汪汪,誰也勸不了' %(person.type, self.type))
class Love(Action):
type = '戀愛'
def GetManConclusion(self, person):
printInfo('%s %s時,凡是不懂也要裝懂' %(person.type, self.type))
def GetWomanConclusion(self, person):
printInfo('%s %s時,遇事懂也裝作不懂' %(person.type, self.type))
#物件結構類:遍歷資料結構的操作
class ObjectStructure:
elements = []
def Attach(self, element):
self.elements.append(element)
def Detach(self, element):
self.elements.remove(element)
def Display(self, visitor):
for e in self.elements:
e.Accept(visitor)
def clientUI():
o = ObjectStructure()
o.Attach(Man())
o.Attach(Woman())
o.Display(Success())
o.Display(Failing())
o.Display(Love())
return
if __name__ == '__main__':
clientUI();
複製程式碼
總結
優點:
1、使得資料結構和作用於結構上的操作解耦,使得操作集合可以獨立變化。
2、新增新的操作或者說訪問者會非常容易。
3、將對各個元素的一組操作集中在一個訪問者類當中。
4、使得類層次結構不改變的情況下,可以針對各個層次做出不同的操作,而不影響類層次結構的完整性。
5、可以跨越類層次結構,訪問不同層次的元素類,做出相應的操作。
缺點:
1、增加新的元素會非常困難。
2、實現起來比較複雜,會增加系統的複雜性。
3、破壞封裝,如果將訪問行為放在各個元素中,則可以不暴露元素的內部結構和狀態,但使用訪問者模式的時候,為了讓訪問者能獲取到所關心的資訊,元素類不得不暴露出一些內部的狀態和結構,就像收入和支出類必須提供訪問金額和單子的專案的方法一樣。
適用性:
1、資料結構穩定,作用於資料結構的操作經常變化的時候。
2、當一個資料結構中,一些元素類需要負責與其不相關的操作的時候,為了將這些操作分離出去,以減少這些元素類的職責時,可以使用訪問者模式。
3、有時在對資料結構上的元素進行操作的時候,需要區分具體的型別,這時使用訪問者模式可以針對不同的型別,在訪問者類中定義不同的操作,從而去除掉型別判斷。