1. 程式人生 > >23種設計模式之訪問者模式

23種設計模式之訪問者模式

訪問者模式的定義

定義: 封裝一些作用於某種資料結構中的各元素的操作, 它可以在不改變資料結構的前提下定義作用於這些元素的新的操作

通俗的說, 就是定義一個訪問者角色, 當對指定角色進行訪問時要通過訪問者進行訪問

其類圖如下:

23種設計模式之訪問者模式

 

各角色說明:

  1. Vistor 抽象訪問者: 抽象類或介面, 宣告訪問者可以訪問哪些元素, 具體到程式中就是 visit 方法的引數定義哪些物件是可以被訪問的
  2. ConcreteVistor 具體訪問者: 它影響訪問者訪問到一個類後該怎麼幹, 要做什麼事
  3. Element 抽象元素: 介面或抽象類, 宣告接受哪一類訪問者訪問, 程式上是通過 accept 方法中的引數來定義的
  4. ConcreteElement 具體元素: 實現 accept方法, 通常是 visitor.visit(this); 基本上都形成一種模式了
  5. ObjectStruture 結構物件: 元素的生成者, 一般容納在多個不同類、不同介面的容器, 專案中一般很少抽象出這個角色

抽象元素程式碼:

23種設計模式之訪問者模式

 

具體元素程式碼:

23種設計模式之訪問者模式

 

抽象訪問者程式碼:

23種設計模式之訪問者模式

 

具體訪問者程式碼:

23種設計模式之訪問者模式

 

結構物件用來產生不同的元素物件, 程式碼如下:

23種設計模式之訪問者模式

 

場景類程式碼:

23種設計模式之訪問者模式

 

通過增加訪問者, 這要是具體元素就非常容易訪問, 對元素的遍歷就更加容易了, 甭管它是什麼物件, 只要它在一個容器中, 都可以通過訪問者來訪問, 任務集中化.

訪問者模式的應用

訪問者模式的優點:

  1. 符合單一職責原則. 具體元素角色負責資料的載入, 而訪問者角色負責報表的展現, 兩個不同的職責非常明確的分離開來, 各自演繹變化
  2. 優秀的擴充套件. 由於職責分開,繼續增加 對資料的操作是非常快捷的.
  3. 靈活性非常高. 例如, 當需要對不同的具體元素進行分別統計時, 使用 instanceof 迴圈判斷當然也可以, 但是現在有一個好辦法, 那就是把它丟給訪問者,由訪問者來進行統計計算

訪問者模式的缺點:

  1. 具體元素對訪問者公佈細節. 訪問者要訪問一個類就必然要求這個類公佈一些方法和資料, 也就是說訪問者關注了其他類的內部細節, 這也是迪米特法則所不建議的
  2. 具體元素變更比較困難. 具體元素角色的增加、刪除、修改是比較困難的
  3. 違背了依賴倒置原則. 訪問者依賴的是具體元素, 而不是抽象元素, 這破壞了依賴倒置原則, 特別是在面向物件的程式設計中, 拋棄了對 介面的依賴,而直接依賴實現類, 擴充套件比較難

訪問者模式的應用場景:

  1. 一個物件結構包含很多類物件, 它們有不同的介面, 而你想對這些物件實施一些依賴於其具體類的操作, 也就是說用迭代器模式已經不能勝任的情景
  2. 需要對一個物件結構中的物件進行很多不同並且不相關的操作, 而你想避免讓這些操作"汙染"這些物件的類
  3. 業務規則要求遍歷多個不同的物件. 這本身也是訪問者模式的出發點, 訪問者模式是對迭代器模式的擴充, 可以便利不同的物件, 然後執行不同的操作, 也就是針對訪問的物件不同,執行不同的操作.
  4. 訪問者模式還有一個 用途, 充當攔截器角色

訪問者模式的擴充套件

1.統計功能

對不同的具體元素進行統計, 針對不同的具體元素針對性統計

比如統計員工工資, 經理和員工的工資情況不同, 使用訪問者進行分別計算, 然後可以計算總額等

2.多個訪問者

可以定義多個訪問者, 每個訪問者實現不同的功能

在IVistor 下再定義 介面繼承 IVistor, 分別實現各自功能, 使用時傳遞不同的訪問者有不同的表現


訪問者模式是一種集中規整模式,特別使用於大規模重構的專案, 在這一個階段需求已經非常清晰, 原系統的功能點也已經明確, 通過訪問者模式可以很容易把一些功能進行梳理, 達到最終目的--功能集中化, 如一個統一的報表運算、UI展現等, 我們還可以與其它模式混編建立一套自己的過濾器或者攔截器


 

 

可以關注一下鄙人的公眾號, 謝謝各位了!