定義
- 表示作用于某對(duì)象結(jié)構(gòu)中的各元素的操作。它可以使你在不改變各元素的類(lèi)的前提下定義作用于這些元素的新操作 [引用大話(huà)設(shè)計(jì)模式概念]
- 維護(hù)了開(kāi)放-封閉原則(拓展開(kāi)放胰苏,更改封閉)
應(yīng)用場(chǎng)景
適用于數(shù)據(jù)結(jié)構(gòu)相對(duì)穩(wěn)定的系統(tǒng)
例:1. apt(注解處理工具)通過(guò)訪問(wèn)者模式解析注解(參照Think in Java P632)逻谦;2.大話(huà)設(shè)計(jì)模式中乒疏,男人和女人對(duì)待不同狀態(tài)做出不同相應(yīng)的例子
優(yōu)缺點(diǎn)
- 優(yōu)點(diǎn)
- 處理與數(shù)據(jù)結(jié)構(gòu)分離(解耦合)
ps: 這里的數(shù)據(jù)結(jié)構(gòu)舉例:人類(lèi)中只有男人女人蓖议,男人和女人就是人類(lèi)的數(shù)據(jù)結(jié)構(gòu) - 使用雙分派
增加新的操作時(shí),只需要增加新的訪問(wèn)者蛮艰,無(wú)需改動(dòng)其他代碼(可參照下例代碼)- 客戶(hù)端調(diào)用時(shí)腋腮,調(diào)用元素的
accept
方法,具體訪問(wèn)者作為參數(shù) -
accept
方法中壤蚜,調(diào)用訪問(wèn)者的方法即寡,并將自己(具體元素)作為參數(shù)傳入
- 客戶(hù)端調(diào)用時(shí)腋腮,調(diào)用元素的
- 增加新的訪問(wèn)者(新的操作)很容易,
- 處理與數(shù)據(jù)結(jié)構(gòu)分離(解耦合)
- 缺點(diǎn)
- 增加新的數(shù)據(jù)結(jié)構(gòu)會(huì)很困難
例如袜刷,人類(lèi)中增加一個(gè)種類(lèi)聪富,那么所有的訪問(wèn)者都要增加一個(gè)對(duì)此種類(lèi)的處理
- 增加新的數(shù)據(jù)結(jié)構(gòu)會(huì)很困難
類(lèi)圖
訪問(wèn)者模式類(lèi)圖.jpg
- 類(lèi)圖中有四個(gè)重要元素:
Visitor
、ConcreteVisitor
水泉、Element
、ConcreteElement
- 抽象訪問(wèn)者(Visitor):為每個(gè)
Element
的實(shí)現(xiàn)聲明一個(gè)Visit
(訪問(wèn))操作窒盐,可為接口或抽象類(lèi) - 具體訪問(wèn)者(ConcreteVisitor):實(shí)現(xiàn)Visitor的操作
實(shí)現(xiàn)具體的訪問(wèn)行為 - 抽象元素(Element):具體數(shù)據(jù)結(jié)構(gòu)的抽象
聲明一個(gè)accept
(接受操作)草则,接受一個(gè)訪問(wèn)者對(duì)象作為參數(shù) - 具體元素(ConcreteVisitor):實(shí)現(xiàn)了抽象元素的
accept
一般會(huì)在accept
方法的實(shí)現(xiàn)中,直接做一次分派
- 抽象訪問(wèn)者(Visitor):為每個(gè)
男人與女人的例子
- 引用大話(huà)設(shè)計(jì)模式中男人和女人的例子
- 男人和女人面對(duì)不同的狀態(tài)蟹漓,有不同的反應(yīng)
- 人類(lèi)(Element)炕横,抽象訪問(wèn)者,擁有一個(gè)
accept
(接受狀態(tài))的方法葡粒,會(huì)面臨多種狀態(tài):成功份殿、失敗、戀愛(ài)嗽交、結(jié)婚 - 男人卿嘲、女人(ConcreteVisitor1、ConcreteVisitor2)夫壁,實(shí)現(xiàn)自己的
accept
(接受狀態(tài)時(shí)的反應(yīng))拾枣。面對(duì)狀態(tài),都會(huì)做出自己的反應(yīng) - 狀態(tài)(Visitor)盒让,定義兩個(gè)方法:男人對(duì)狀態(tài)的反應(yīng)梅肤、女人對(duì)狀態(tài)的反應(yīng)
- 具體狀態(tài)(戀愛(ài)、失敗等)(ConcreteVisitor1邑茄、ConcreteVisitor2姨蝴、ConcreteVisitor3、ConcreteVisitor4...)
- 人類(lèi)(Element)炕横,抽象訪問(wèn)者,擁有一個(gè)
訪問(wèn)者模式代碼:
- 抽象元素:人類(lèi)
/**
* Element(抽象元素):人類(lèi)
*/
public interface Person {
/**
* 接受狀態(tài)
* @param action
*/
String accept(Action action);
}
- 抽象訪問(wèn)者:
/**
* Action(抽象訪問(wèn)者):狀態(tài)
*/
public interface Action {
/**
* 獲取男人的反應(yīng)
* @param person
* @return
*/
String GetManConclusion(Man person);
/**
* 獲取女人反應(yīng)
* @param person
* @return
*/
String GetManConclusion(Woman person);
}
- 具體元素:男人肺缕、女人
男人
/**
* ConcreteElement(抽象訪問(wèn)者): 男人
*/
public class Man implements Person {
@Override
public String accept(Action action) {
// 第二次分派左医,調(diào)用action(訪問(wèn)者)的方法授帕,把自己(元素本身)作為參數(shù)傳入
return action.GetManConclusion(this);
}
}
女人
/**
* ConcreteElement(抽象訪問(wèn)者): 女人
*/
public class Woman implements Person {
@Override
public String accept(Action action) {
// 第二次分派,調(diào)用action(訪問(wèn)者)的方法炒辉,把自己(元素本身)作為參數(shù)傳入
return action.GetManConclusion(this);
}
}
- 具體狀態(tài):成功豪墅、失敗、戀愛(ài)等等
成功
/**
* ConcreteVisitor(具體訪問(wèn)者): 成功狀態(tài)的響應(yīng)
*/
public class Success implements Action {
@Override
public String GetManConclusion(Man person) {
return "男人成功時(shí)黔寇,背后總有一個(gè)偉大的女人";
}
@Override
public String GetManConclusion(Woman person) {
return "女人成功時(shí)偶器,背后大多有一個(gè)不成功的男人";
}
}
失敗
/**
* ConcreteVisitor(具體訪問(wèn)者): 失敗狀態(tài)的響應(yīng)
*/
public class Failure implements Action {
@Override
public String GetManConclusion(Man person) {
return "男人失敗時(shí),悶頭喝酒缝裤,誰(shuí)也不用勸";
}
@Override
public String GetManConclusion(Woman person) {
return "女人失敗時(shí)屏轰,眼淚汪汪,誰(shuí)也勸不了";
}
}
戀愛(ài)
/**
* ConcreteVisitor(具體訪問(wèn)者): 戀愛(ài)狀態(tài)的響應(yīng)
*/
public class Love implements Action{
@Override
public String GetManConclusion(Man person) {
return "男人戀愛(ài)是憋飞,凡事不懂也要裝懂";
}
@Override
public String GetManConclusion(Woman person) {
return "女人戀愛(ài)時(shí)霎苗,遇事懂也裝作不懂";
}
}
- 枚舉元素
/**
* 用來(lái)枚舉元素,包含多個(gè)元素
*/
public class ObjectStructure {
private List<Person> elements = new ArrayList<>();
public void add(Person person) {
if (null != person) {
this.elements.add(person);
}
}
public void del(Person person) {
if (null != person) {
this.elements.remove(person);
}
}
/**
* 獲取并展示元素對(duì)指定狀態(tài)的響應(yīng)
* @param action 指定狀態(tài)
*/
public void accept(Action action) {
if (null == this.elements || 0 >= this.elements.size()) {
return;
}
this.elements.forEach(element -> {
// 第一次分派榛做,調(diào)用元素的接受狀態(tài)方法唁盏,將action(訪問(wèn)者)作為參入
String result = element.accept(action);
System.out.println("person: " + element.getClass().getName() + "action: " + action.getClass().getName() +
"conclusion: " + result);
});
}
}