一、基礎(chǔ)簡介
1、定義
表示一個作用于某對象結(jié)構(gòu)中的各元素的操作训唱。它使你可以在不改變各元素的類的前提下定義作用于這些元素的新操作。
通過這種方式挚冤,元素的執(zhí)行算法可以隨著訪問者改變而改變况增。這種類型的設(shè)計模式屬于行為型模式。
2训挡、使用場景
- 一個對象結(jié)構(gòu)包含多個類型的對象澳骤,希望對這些對象實施一些依賴其具體類型的操作。在訪問者中針對每一種具體的類型都提供了一個訪問操作澜薄,不同類型的對象可以有不同的訪問操作为肮。
- 需要對一個對象結(jié)構(gòu)中的對象進(jìn)行很多不同的并且不相關(guān)的操作,而需要避免讓這些操作“污染”這些對象的類肤京,也不希望在增加新操作時修改這些類颊艳。訪問者模式使得我們可以將相關(guān)的訪問操作集中起來定義在訪問者類中,對象結(jié)構(gòu)可以被多個不同的訪問者類所使用忘分,將對象本身與對象的訪問操作分離棋枕。
- 對象結(jié)構(gòu)中對象對應(yīng)的類很少改變,但經(jīng)常需要在此對象結(jié)構(gòu)上定義新的操作妒峦。
3重斑、優(yōu)缺點
優(yōu)點: 1、符合單一職責(zé)原則肯骇。 2窥浪、優(yōu)秀的擴(kuò)展性祖很。 3、靈活性漾脂。
缺點: 1假颇、具體元素對訪問者公布細(xì)節(jié),違反了迪米特原則符相。 2拆融、具體元素變更比較困難。 3啊终、違反了依賴倒置原則镜豹,依賴了具體類,沒有依賴抽象蓝牲。
4趟脂、模式結(jié)構(gòu)分析
- Visitor(抽象訪問者):抽象訪問者為對象結(jié)構(gòu)中每一個具體元素類ConcreteElement聲明一個訪問操作,從這個操作的名稱或參數(shù)類型可以清楚知道需要訪問的具體元素的類型例衍,具體訪問者需要實現(xiàn)這些操作方法昔期,定義對這些元素的訪問操作。
- ConcreteVisitor(具體訪問者):具體訪問者實現(xiàn)了每個由抽象訪問者聲明的操作佛玄,每一個操作用于訪問對象結(jié)構(gòu)中一種類型的元素硼一。
- Element(抽象元素):抽象元素一般是抽象類或者接口,它定義一個accept()方法梦抢,該方法通常以一個抽象訪問者作為參數(shù)般贼。
- ConcreteElement(具體元素):具體元素實現(xiàn)了accept()方法,在accept()方法中調(diào)用訪問者的訪問方法以便完成對一個元素的操作奥吩。
- ObjectStructure(對象結(jié)構(gòu)):對象結(jié)構(gòu)是一個元素的集合哼蛆,它用于存放元素對象,并且提供了遍歷其內(nèi)部元素的方法霞赫。它可以結(jié)合組合模式來實現(xiàn)腮介,也可以是一個簡單的集合對象,如一個List對象或一個Set對象端衰。
二叠洗、實例實現(xiàn)
1、實例場景
比如說旅东,男人和女人面對成功與失敗惕味,會有不同的反應(yīng)或結(jié)論:
- 1)男人成功時,背后都有一個偉大的女人玉锌;女人成功時,背后都有一群男人
- 2)男人失敗時疟羹,悶頭喝酒主守,誰也不用勸禀倔;女人失敗時,眼淚汪汪参淫,誰也勸不了
這里救湖,Element就是“人類”,ConcreteElementA和ConcreteElementB就是“Man”和“Woman”涎才,而Visitor就是不同的“狀態(tài)”鞋既,ConcreteVisitor就是“成功”、“失敗”等具體的狀態(tài)場景耍铜。
- 使用“訪問者模式”邑闺,如果需要新增一個狀態(tài)(比如結(jié)婚、挫折等狀態(tài))棕兼,只需要增加一個ConcreteVisitor即可陡舅。
2、Element(抽象元素)
package com.mfc.design.訪問者模式;
/**
* @author MouFangCai
* @date 2019/10/28 16:06
*
* @description Element(抽象元素)
*/
public abstract class Person {
// 用來獲得“行為”對象的
abstract void accept(Action visitor);
}
3伴挚、ConcreteElement(具體元素)
package com.mfc.design.訪問者模式;
/**
* @author MouFangCai
* @date 2019/10/28 16:11
*
* @description ConcreteElement(具體元素)
*/
public class Man extends Person {
@Override
void accept(Action visitor) {
visitor.getManReact(this);
}
}
package com.mfc.design.訪問者模式;
/**
* @author MouFangCai
* @date 2019/10/28 16:11
*
* @description ConcreteElement(具體元素)
*/
public class Woman extends Person {
@Override
void accept(Action visitor) {
visitor.getWomanReact(this);
}
}
4靶衍、Visitor(抽象訪問者)
package com.mfc.design.訪問者模式;
/**
* @author MouFangCai
* @date 2019/10/28 16:07
*
* @description Visitor(抽象訪問者)
*/
public interface Action {
// 得到Man的反應(yīng)
void getManReact(Man concreteElementA);
// 得到Woman的反應(yīng)
void getWomanReact(Woman concreteElementB);
}
5、雙分派技術(shù)
在這里茎芋,Action的 getManReact(Man concreteElementA) 方法與 Man 里的
** void accept(Action visitor) {**
** visitor.getManReact(this);
}**方法颅眶,充分利用雙分派技術(shù),實現(xiàn)了處理與數(shù)據(jù)結(jié)構(gòu)的分離田弥。
結(jié)合該實例的完整代碼理解該技術(shù):
- 首先涛酗,在客戶端,將“具體的狀態(tài)”作為參數(shù)傳遞給“具體的Element”皱蹦,完成第一分派煤杀;
// 客戶端 PersonList persons = new PersonList(); persons.add(new Man()); persons.add(new Woman()); // 成功時 Success s = new Success(); persons.display(s);
// persons里的方法 // 查看顯示 public void display(Action visitor) { for (Person p : list) { p.accept(visitor); } }
- 然后,“具體的Element”類——Man沪哺,調(diào)用作為參數(shù)的“具體的狀態(tài)”中的方法“void getManReact(Man concreteElementA);” 沈自,同時將自己(this)作為參數(shù)傳遞進(jìn)去。完成第二次分派辜妓。
public class Man extends Person { @Override void accept(Action visitor) { visitor.getManReact(this); } }
6枯途、ConcreteVisitor(具體訪問者)
package com.mfc.design.訪問者模式;
/**
* @author MouFangCai
* @date 2019/10/28 16:14
*
* @description ConcreteVisitor(具體訪問者)
*/
public class Failure implements Action {
@Override
public void getManReact(Man concreteElementA) {
System.out.println("男人失敗時,悶頭喝酒籍滴,誰也不用勸");
}
@Override
public void getWomanReact(Woman concreteElementB) {
System.out.println("女人失敗時酪夷,眼淚汪汪,誰也勸不了");
}
}
package com.mfc.design.訪問者模式;
/**
* @author MouFangCai
* @date 2019/10/28 16:14
*
* @description ConcreteVisitor(具體訪問者)
*/
public class Success implements Action {
@Override
public void getManReact(Man concreteElementA) {
System.out.println("男人成功時孽惰,背后都有一個偉大的女人");
}
@Override
public void getWomanReact(Woman concreteElementB) {
System.out.println("女人成功時晚岭,背后都有一群男人");
}
}
7、ObjectStructure(對象結(jié)構(gòu)):對象結(jié)構(gòu)是一個元素的集合
package com.mfc.design.訪問者模式;
import java.util.ArrayList;
import java.util.List;
/**
* @author MouFangCai
* @date 2019/10/28 16:20
*
* @description ObjectStructure(對象結(jié)構(gòu)):對象結(jié)構(gòu)是一個元素的集合
*/
public class PersonList {
private List<Person> list = new ArrayList<>();
public void add(Person element) {
list.add(element);
}
public void delete(Person element) {
list.remove(element);
}
// 查看顯示
public void display(Action visitor) {
for (Person p : list) {
p.accept(visitor);
}
}
}
8勋功、客戶端
package com.mfc.design.訪問者模式;
/**
* @author MouFangCai
* @date 2019/10/28 16:23
* @description
*/
public class Client_visitor {
public static void main(String[] args) {
PersonList persons = new PersonList();
persons.add(new Man());
persons.add(new Woman());
// 成功時
Success s = new Success();
persons.display(s);
// 失敗時
Failure f = new Failure();
persons.display(f);
}
}
9坦报、結(jié)果展示
男人成功時库说,背后都有一個偉大的女人
女人成功時,背后都有一群男人
男人失敗時片择,悶頭喝酒潜的,誰也不用勸
女人失敗時,眼淚汪汪字管,誰也勸不了Process finished with exit code 0