訪問(wèn)者模式

定義

  • 表示作用于某對(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)其他代碼(可參照下例代碼)
      1. 客戶(hù)端調(diào)用時(shí)腋腮,調(diào)用元素的accept方法,具體訪問(wèn)者作為參數(shù)
      2. accept方法中壤蚜,調(diào)用訪問(wèn)者的方法即寡,并將自己(具體元素)作為參數(shù)傳入
    • 增加新的訪問(wèn)者(新的操作)很容易,
  • 缺點(diǎn)
    • 增加新的數(shù)據(jù)結(jié)構(gòu)會(huì)很困難
      例如袜刷,人類(lèi)中增加一個(gè)種類(lèi)聪富,那么所有的訪問(wèn)者都要增加一個(gè)對(duì)此種類(lèi)的處理

類(lèi)圖

訪問(wèn)者模式類(lèi)圖.jpg
  • 類(lèi)圖中有四個(gè)重要元素:VisitorConcreteVisitor水泉、ElementConcreteElement
    1. 抽象訪問(wèn)者(Visitor):為每個(gè)Element的實(shí)現(xiàn)聲明一個(gè)Visit(訪問(wèn))操作窒盐,可為接口或抽象類(lèi)
    2. 具體訪問(wèn)者(ConcreteVisitor):實(shí)現(xiàn)Visitor的操作
      實(shí)現(xiàn)具體的訪問(wèn)行為
    3. 抽象元素(Element):具體數(shù)據(jù)結(jié)構(gòu)的抽象
      聲明一個(gè)accept(接受操作)草则,接受一個(gè)訪問(wèn)者對(duì)象作為參數(shù)
    4. 具體元素(ConcreteVisitor):實(shí)現(xiàn)了抽象元素的accept
      一般會(huì)在accept方法的實(shí)現(xiàn)中,直接做一次分派

男人與女人的例子

  • 引用大話(huà)設(shè)計(jì)模式中男人和女人的例子
  • 男人和女人面對(duì)不同的狀態(tài)蟹漓,有不同的反應(yīng)
    1. 人類(lèi)(Element)炕横,抽象訪問(wèn)者,擁有一個(gè)accept(接受狀態(tài))的方法葡粒,會(huì)面臨多種狀態(tài):成功份殿、失敗、戀愛(ài)嗽交、結(jié)婚
    2. 男人卿嘲、女人(ConcreteVisitor1、ConcreteVisitor2)夫壁,實(shí)現(xiàn)自己的accept(接受狀態(tài)時(shí)的反應(yīng))拾枣。面對(duì)狀態(tài),都會(huì)做出自己的反應(yīng)
    3. 狀態(tài)(Visitor)盒让,定義兩個(gè)方法:男人對(duì)狀態(tài)的反應(yīng)梅肤、女人對(duì)狀態(tài)的反應(yīng)
    4. 具體狀態(tài)(戀愛(ài)、失敗等)(ConcreteVisitor1邑茄、ConcreteVisitor2姨蝴、ConcreteVisitor3、ConcreteVisitor4...)
訪問(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);
        });
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市检眯,隨后出現(xiàn)的幾起案子厘擂,更是在濱河造成了極大的恐慌,老刑警劉巖锰瘸,帶你破解...
    沈念sama閱讀 218,607評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件刽严,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡避凝,警方通過(guò)查閱死者的電腦和手機(jī)舞萄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)管削,“玉大人倒脓,你說(shuō)我怎么就攤上這事『迹” “怎么了把还?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,960評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)茸俭。 經(jīng)常有香客問(wèn)我吊履,道長(zhǎng),這世上最難降的妖魔是什么调鬓? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,750評(píng)論 1 294
  • 正文 為了忘掉前任艇炎,我火速辦了婚禮,結(jié)果婚禮上腾窝,老公的妹妹穿的比我還像新娘缀踪。我一直安慰自己居砖,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,764評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布驴娃。 她就那樣靜靜地躺著奏候,像睡著了一般。 火紅的嫁衣襯著肌膚如雪唇敞。 梳的紋絲不亂的頭發(fā)上蔗草,一...
    開(kāi)封第一講書(shū)人閱讀 51,604評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音疆柔,去河邊找鬼咒精。 笑死,一個(gè)胖子當(dāng)著我的面吹牛旷档,可吹牛的內(nèi)容都是我干的模叙。 我是一名探鬼主播,決...
    沈念sama閱讀 40,347評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼鞋屈,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼范咨!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起厂庇,我...
    開(kāi)封第一講書(shū)人閱讀 39,253評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤渠啊,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后宋列,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體昭抒,經(jīng)...
    沈念sama閱讀 45,702評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡评也,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,893評(píng)論 3 336
  • 正文 我和宋清朗相戀三年炼杖,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片盗迟。...
    茶點(diǎn)故事閱讀 40,015評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡坤邪,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出罚缕,到底是詐尸還是另有隱情艇纺,我是刑警寧澤,帶...
    沈念sama閱讀 35,734評(píng)論 5 346
  • 正文 年R本政府宣布邮弹,位于F島的核電站黔衡,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏腌乡。R本人自食惡果不足惜盟劫,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,352評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望与纽。 院中可真熱鬧侣签,春花似錦塘装、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,934評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至猴娩,卻和暖如春阴幌,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背胀溺。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,052評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工裂七, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人仓坞。 一個(gè)月前我還...
    沈念sama閱讀 48,216評(píng)論 3 371
  • 正文 我出身青樓背零,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親无埃。 傳聞我的和親對(duì)象是個(gè)殘疾皇子徙瓶,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,969評(píng)論 2 355