【設計模式】詳解訪問者(Visitor)模式-有多段程式碼出沒
場景切入
動物園中有多個場館,比如豹子館,海豚館,大象館等等,有些場館是需要特殊收費的,動物園針對不同型別的遊客有不同的收費方式,比如學生半價。
這個場景下,包括以下要素:動物園
,動物園中的各個場館
,不同型別的遊客
,不同型別的遊客票價不同
。
動物園就相當於一個物件結構
,該結構包含具體的元素
-各個場館,每個場館(元素)都有接待遊客
(visitor)的方法(accept)。
這些被處理的資料元素相對穩定(動物園中的場館一般比較穩定)而訪問方式多種多樣(比如學生散客,學生團體,普通遊客,團體遊客等不同的訪問方式)的資料結構,如果用“訪問者模式”來處理比較方便。
訪問者模式能把處理方法從資料結構中分離出來,並可以根據需要增加新的處理方法,且不用修改原來的程式程式碼與資料結構,這提高了程式的擴充套件性和靈活性。
訪問者模式的結構
通過上面場景的分析,訪問者(Visitor)模式實現的關鍵是如何將作用於元素的操作分離出來封裝成獨立的類,其基本結構如下:
- 抽象的訪問者(Visitor):訪問具體元素的介面,為每個具體元素類對應一個訪問操作
visitXX()
,其引數為某個具體的元素。 - 具體的訪問者(ConcreteVisitor):實現抽象訪問者角色中宣告的各個訪問操作,確定訪問者訪問一個元素時該做什麼。
- 抽象元素(Element):宣告一個包含接受操作
accept()
的介面,其引數為訪問者物件(遊客
)。 - 具體元素(ConcreteElement):實現抽象元素角色提供的 accept() 操作,其方法體通常都是 visitor.visitXX(this) ,另外具體元素中可能還包含本身業務邏輯的相關操作。
- 物件結構(Object Structure):一個包含元素角色的容器,提供讓訪問者物件遍歷容器中的所有元素的方法,通常由 List、Set、Map 等聚合類實現。本例中的
動物園
就可抽象成一個物件結構。
針對我之前設定的動物園場景,用訪問者模式實現的類圖為:
程式碼實現
前面已經分析出需要抽象出來的類了,我們把它們轉化成程式碼。
物件結構(Object Structure):
//物件結構角色:動物園
class Zoo {
//場館集合
private List<ScenerySpot> list = new ArrayList<>();
//接待遊客
public void accept(Visitor visitor) {
for (ScenerySpot scenerySpot : list) {
scenerySpot.accept(visitor);
}
}
public void add(ScenerySpot scenerySpot) {
list.add(scenerySpot);
}
public void remove(ScenerySpot scenerySpot) {
list.remove(scenerySpot);
}
}
抽象元素和具體元素:
//抽象元素:場館景點
interface ScenerySpot {
//接待訪問者
void accept(Visitor visitor);
//票價(單位是分)
Integer ticketRate();
}
//具體元素:豹子館
class LeopardSpot implements ScenerySpot {
@Override
public void accept(Visitor visitor) {
visitor.visitLeopardSpot(this);
}
@Override
public Integer ticketRate() {
//票價15元
return 1500;
}
}
//具體元素:海豚館
class DolphinSpot implements ScenerySpot {
@Override
public void accept(Visitor visitor) {
visitor.visitDolphinSpot(this);
}
@Override
public Integer ticketRate() {
//票價20元
return 2000;
}
}
抽象訪問者和具體訪問者:
//抽象訪問者:遊客
interface Visitor {
//參觀獵豹館
void visitLeopardSpot(LeopardSpot leopardSpot);
//參觀海豚館
void visitDolphinSpot(DolphinSpot dolphinSpot);
}
//具體的訪問者:學生遊客
class StudentVisitor implements Visitor {
@Override
public void visitLeopardSpot(LeopardSpot leopardSpot) {
//學生票打五折
int v = (int) (leopardSpot.ticketRate() * 0.5);
System.out.println("學生遊客遊覽豹子館票價:" + v);
}
@Override
public void visitDolphinSpot(DolphinSpot dolphinSpot) {
//學生票打五折
int v = (int) (dolphinSpot.ticketRate() * 0.5);
System.out.println("學生遊客遊覽海豚館票價:" + v);
}
}
//具體的訪問者:普通遊客
class CommonVisitor implements Visitor {
@Override
public void visitLeopardSpot(LeopardSpot leopardSpot) {
System.out.println("普通遊客遊覽豹子館票價:" + leopardSpot.ticketRate());
}
@Override
public void visitDolphinSpot(DolphinSpot dolphinSpot) {
System.out.println("普通遊客遊覽海豚館票價:" + dolphinSpot.ticketRate());
}
}
使用:
public class VisitorPattern {
public static void main(String[] args) {
Zoo zoo = new Zoo();
//新增遊覽的場館
zoo.add(new LeopardSpot());
zoo.add(new DolphinSpot());
//還可以新增其他場館
//動物園接待不同型別的遊客
//學生遊客
zoo.accept(new StudentVisitor());
System.out.println("==========================");
//普通遊客
zoo.accept(new CommonVisitor());
//還可以定義其他型別的遊客,比如公司團體遊客等
}
}
執行結果:
學生遊客遊覽豹子館票價:750
學生遊客遊覽海豚館票價:1000
==========================
普通遊客遊覽豹子館票價:1500
普通遊客遊覽海豚館票價:2000
從程式碼也可以看出來,我們不需要再動動物園 Zoo
這個結構內部的內容了,需要建造場館實現ScenerySpot
,或者接待其他型別的遊客實現Visitor
即可。
應用場景
通常在以下情況可以考慮使用訪問者(Visitor)模式:
- 物件結構相對穩定,但其操作演算法經常變化的程式。
- 物件結構中的物件需要提供多種不同且不相關的操作,而且要避免讓這些操作的變化影響物件的結構。
- 物件結構包含很多型別的物件,希望對這些物件實施一些依賴於其具體型別的操作。
其他設計模式閱讀
- 淺析單例模式的8種寫法
- 【設計模式】策略模式之“這不就是if-else嗎”
- 【設計模式】工廠系列-FactoryMethod,AbstractFactory,Spring IOC
- 【設計模式】幾需體驗三歡鍾,裡造會幹我一樣理解Facade和Mediator模式
- 【設計模式】代理模式那些事兒:靜態代理,動態代理,JDK的動態代理,cglib,Spring AOP
- 【設計模式】慎用多層繼承,不妨試試裝飾器模式
- 【設計模式】責任鏈模式-號稱倒數第二難的設計模式終於搞明白了
- 【設計模式】Observer 觀察者模式淺析
- 這就是模板方法?TemplateMethod,一個你一直都在用的設計模式!
- 【設計模式】Prototype原型模式
您的點贊,我的動力!
本文已收錄github:https://github.com/xblzer/JavaJourney
微信搜公眾號 行百里er,獲取更多幹貨文章。
相關文章
- C++設計模式 - 訪問器模式(Visitor)C++設計模式
- 設計模式(十六)——訪問者模式設計模式
- 極簡設計模式-訪問者模式設計模式
- 九、GO 程式設計模式:K8S VISITOR 模式Go程式設計設計模式K8S
- 設計模式 - ASM 中的訪問者模式設計模式ASM
- 設計模式學習之訪問者模式設計模式
- C#設計模式之訪問者模式C#設計模式
- 【趣味設計模式系列】之【訪問者模式】設計模式
- 15.java設計模式之訪問者模式Java設計模式
- 設計模式【4】-- 建造者模式詳解設計模式
- Android理解設計模式之組合模式、迭代器模式、訪問者模式Android設計模式
- 設計模式(二十三)訪問者設計模式
- Java進階篇設計模式之十 ---- 訪問者模式和中介者模式Java設計模式
- 深入淺出訪問者模式模式
- 設計模式學習-使用go實現訪問者模式設計模式Go
- 「補課」進行時:設計模式(18)——訪問者模式設計模式
- 軟體設計模式系列之二十五——訪問者模式設計模式
- 軟體設計模式學習(二十七)訪問者模式設計模式
- 設計模式 - 代理模式詳解設計模式
- 設計模式:代理模式詳解設計模式
- 行為型設計模式 - 觀察者模式詳解設計模式
- 訪問者模式模式
- 【程式碼簡述設計模式】----- 觀察者模式設計模式
- 行為模式-訪問者模式模式
- 設計模式詳解設計模式
- c#中建造者設計模式詳解C#設計模式
- 設計模式之單例模式詳解設計模式單例
- Android原始碼設計模式-中介者模式Android原始碼設計模式
- iOS設計模式詳解iOS設計模式
- [提問交流]有段程式碼沒看懂
- 設計模式學習筆記(二十一)訪問者模式及其實現設計模式筆記
- 聊聊OOP中的設計原則以及訪問者模式OOP模式
- python-訪問者模式Python模式
- 設計模式之單例、工廠、釋出訂閱者模式設計模式設計模式單例
- Javascript設計模式Revealing Module 揭示模式單例模式詳解JavaScript設計模式單例
- 四種設計模式詳解設計模式
- 詳解模板方法設計模式設計模式
- GoLang設計模式17 - 訪客模式Golang設計模式