設(shè)計(jì)模式系列:一文帶你領(lǐng)略“訪問(wèn)者模式”的魅力
訪問(wèn)者模式相對(duì)來(lái)說(shuō)比較抽象和難以理解,可能單純地通過(guò)文字、類圖、案例代碼大家還是不太容易理解該模式,不過(guò)希望大家不要急躁,可以靜下心來(lái)用心的體會(huì)該設(shè)計(jì)模式的魅力。相信你一定會(huì)有所收獲。
基本介紹
訪問(wèn)者模式的基本概念:封裝一些作用于某種數(shù)據(jù)結(jié)構(gòu)中元素上的操作。其有一個(gè)重要的特征是可以在不改變數(shù)據(jù)結(jié)構(gòu)的前提下定義一些新的操作。
簡(jiǎn)單來(lái)說(shuō)訪問(wèn)者模式主要的作用就是將“數(shù)據(jù)結(jié)構(gòu)”和“數(shù)據(jù)操作”進(jìn)行分離,解決這兩者之間耦合性的問(wèn)題。
訪問(wèn)者模式的基本執(zhí)行原理就是在被訪問(wèn)的類里添加一個(gè)接口,用于接待訪問(wèn)者。
一般數(shù)情況下,當(dāng)我們需要對(duì)一個(gè)數(shù)據(jù)結(jié)構(gòu)中的元素進(jìn)行很多不同的操作,并且這些操作彼此之間并沒(méi)有關(guān)聯(lián),同時(shí)我們還想做到避免因?yàn)檫@些操作而“污染”了這些元素時(shí),就可考慮使用訪問(wèn)者模式。
訪問(wèn)者模式UML類圖

類圖講解
Visitor:抽象訪問(wèn)角色;通常情況下該數(shù)據(jù)結(jié)構(gòu)中有幾個(gè)元素就會(huì)對(duì)應(yīng)的在該類中為每一個(gè)元素提供一個(gè)訪問(wèn)操作(方法)。
ConcreteVisitor:具體訪問(wèn)者角色;繼承了Visitor并實(shí)現(xiàn)了其中定義的所以方法。
Element:抽象元素角色;該類會(huì)定義一個(gè)accept(接收)方法,用于接收訪問(wèn)者。
ConcreteElement:具體元素角色;繼承了Element并實(shí)現(xiàn)了其中定義的accept方法。
ObjectStruture:該類定義了數(shù)據(jù)結(jié)構(gòu)(對(duì)象結(jié)構(gòu)),管理了所有元素,并且可以枚舉它的元素(也就是遍歷)。
案例講解
案例:開發(fā)一個(gè)員工審批功能,具體為不同角色的員工可以進(jìn)行“同意”和“不同意”的審批。
抽象員工類 => 對(duì)應(yīng)Element(抽象元素角色)
- public abstract class Workers {
- // 提供一個(gè)讓訪問(wèn)者訪問(wèn)的方法
- public abstract void accept(Action action);
- }
具體員工類
- /**
- * 經(jīng)理
- */
- public class Manager extends Workers {
- /**
- * 這里用到了雙分派。
- * 第一次分派:在客戶端中將具體的Action作為參數(shù)傳遞到Manager中。
- * 第二次分派:Manager類調(diào)用Action中的具體方法,并將自己作為參數(shù)傳入。
- */
- @Override
- public void accept(Action action) {
- action.managerVerify(this);
- }
- }
- /**
- * 組長(zhǎng)
- */
- public class GroupLeader extends Workers {
- @Override
- public void accept(Action action) {
- action.groupLeaderVerify(this);
- }
- }
抽象行為類 => 對(duì)應(yīng)Visitor(抽象訪問(wèn)角色)
- public abstract class Action {
- // 經(jīng)理進(jìn)行審批
- public abstract void managerVerify(Manager manager);
- // 組長(zhǎng)進(jìn)行審批
- public abstract void groupLeaderVerify(GroupLeader groupLeader);
- }
具體行為類
- /**
- * 同意
- */
- public class Agree extends Action {
- @Override
- public void managerVerify(Manager manager) {
- System.out.println("經(jīng)理的審核結(jié)果為同意!");
- }
- @Override
- public void groupLeaderVerify(GroupLeader groupLeader) {
- System.out.println("組長(zhǎng)的審核結(jié)果為同意!");
- }
- }
- /**
- * 不同意
- */
- public class Disagree extends Action {
- @Override
- public void managerVerify(Manager manager) {
- System.out.println("經(jīng)理的審核結(jié)果為不同意!");
- }
- @Override
- public void groupLeaderVerify(GroupLeader groupLeader) {
- System.out.println("組長(zhǎng)的審核結(jié)果為不同意!");
- }
- }
ObjectStructure類
- public class ObjectStructure {
- // 維護(hù)了一個(gè)集合
- private List<Workers> peoples = new ArrayList<>();
- // 增加
- public void attach(Workers workers) {
- peoples.add(workers);
- }
- // 移除
- public void detach(Workers workers) {
- peoples.remove(workers);
- }
- // 顯示測(cè)評(píng)情況
- public void display(Action action) {
- for (Workers people : peoples) {
- people.accept(action);
- }
- }
- }
客戶端測(cè)試類
- public class Client {
- public static void main(String[] args) {
- ObjectStructure objectStructure = new ObjectStructure();
- // 添加人
- objectStructure.attach(new Manager());
- objectStructure.attach(new GroupLeader());
- // 同意
- Agree agree = new Agree();
- objectStructure.display(agree);
- }
- }
執(zhí)行結(jié)果

總結(jié)
優(yōu)點(diǎn):
1、訪問(wèn)者模式符合單一職責(zé)原則。
2、可以讓數(shù)據(jù)結(jié)構(gòu)和數(shù)據(jù)操作之間解耦。
3、避免了因?yàn)椴僮髟囟鴮?duì)其造成污染的問(wèn)題。
4、讓程序具有擴(kuò)展性的情況下還大大增加了靈活性。
缺點(diǎn):
1、因?yàn)榫唧w的元素對(duì)訪問(wèn)者公布了實(shí)現(xiàn)細(xì)節(jié),所以訪問(wèn)者模式是違背了迪米特法則的。這樣做會(huì)導(dǎo)致元素變化比較困難。
2、因?yàn)樵L問(wèn)者依賴的是具體的元素而不是其抽象父類,所有該模式還違背了依賴倒轉(zhuǎn)原則。
總結(jié) :訪問(wèn)者模式適用于數(shù)據(jù)結(jié)構(gòu)相對(duì)穩(wěn)定并且功能需求還經(jīng)常變化的系統(tǒng)。