訪問者模式——元素的執(zhí)行算法隨著訪問者改變而改變

一、基礎(chǔ)簡介

1、定義

表示一個作用于某對象結(jié)構(gòu)中的各元素的操作训唱。它使你可以在不改變各元素的類的前提下定義作用于這些元素的新操作。

通過這種方式挚冤,元素的執(zhí)行算法可以隨著訪問者改變而改變况增。這種類型的設(shè)計模式屬于行為型模式

2训挡、使用場景

  1. 一個對象結(jié)構(gòu)包含多個類型的對象澳骤,希望對這些對象實施一些依賴其具體類型的操作。在訪問者中針對每一種具體的類型都提供了一個訪問操作澜薄,不同類型的對象可以有不同的訪問操作为肮。
  2. 需要對一個對象結(jié)構(gòu)中的對象進(jìn)行很多不同的并且不相關(guān)的操作,而需要避免讓這些操作“污染”這些對象的類肤京,也不希望在增加新操作時修改這些類颊艳。訪問者模式使得我們可以將相關(guān)的訪問操作集中起來定義在訪問者類中,對象結(jié)構(gòu)可以被多個不同的訪問者類所使用忘分,將對象本身與對象的訪問操作分離棋枕。
  3. 對象結(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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末啰挪,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子嘲叔,更是在濱河造成了極大的恐慌亡呵,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,888評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件借跪,死亡現(xiàn)場離奇詭異政己,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)掏愁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,677評論 3 399
  • 文/潘曉璐 我一進(jìn)店門歇由,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人果港,你說我怎么就攤上這事沦泌。” “怎么了辛掠?”我有些...
    開封第一講書人閱讀 168,386評論 0 360
  • 文/不壞的土叔 我叫張陵谢谦,是天一觀的道長。 經(jīng)常有香客問我萝衩,道長回挽,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,726評論 1 297
  • 正文 為了忘掉前任猩谊,我火速辦了婚禮千劈,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘牌捷。我一直安慰自己墙牌,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,729評論 6 397
  • 文/花漫 我一把揭開白布暗甥。 她就那樣靜靜地躺著喜滨,像睡著了一般。 火紅的嫁衣襯著肌膚如雪撤防。 梳的紋絲不亂的頭發(fā)上虽风,一...
    開封第一講書人閱讀 52,337評論 1 310
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼焰情。 笑死陌凳,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的内舟。 我是一名探鬼主播,決...
    沈念sama閱讀 40,902評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼初橘,長吁一口氣:“原來是場噩夢啊……” “哼验游!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起保檐,我...
    開封第一講書人閱讀 39,807評論 0 276
  • 序言:老撾萬榮一對情侶失蹤耕蝉,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后夜只,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體垒在,經(jīng)...
    沈念sama閱讀 46,349評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,439評論 3 340
  • 正文 我和宋清朗相戀三年扔亥,在試婚紗的時候發(fā)現(xiàn)自己被綠了场躯。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,567評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡旅挤,死狀恐怖踢关,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情粘茄,我是刑警寧澤签舞,帶...
    沈念sama閱讀 36,242評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站柒瓣,受9級特大地震影響儒搭,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜芙贫,卻給世界環(huán)境...
    茶點故事閱讀 41,933評論 3 334
  • 文/蒙蒙 一搂鲫、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧屹培,春花似錦默穴、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,420評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至媒吗,卻和暖如春仑氛,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,531評論 1 272
  • 我被黑心中介騙來泰國打工锯岖, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留介袜,地道東北人。 一個月前我還...
    沈念sama閱讀 48,995評論 3 377
  • 正文 我出身青樓出吹,卻偏偏與公主長得像遇伞,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子捶牢,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,585評論 2 359

推薦閱讀更多精彩內(nèi)容