21_訪問者模式

  • 封裝一些作用于某種數(shù)據(jù)結(jié)構(gòu)中的各元素的操作,它可以在不改變這個(gè)數(shù)據(jù)結(jié)構(gòu)的前提下定義作用于這些元素的新操作摆霉。

結(jié)構(gòu)

  • 抽象訪問者(Visitor)角色:定義了對(duì)每一個(gè)元素(Element)訪問的行為群嗤,它的參數(shù)就是可以訪問的元素,它的方法個(gè)數(shù)理論上來講與元素類個(gè)數(shù)(Element的實(shí)現(xiàn)類個(gè)數(shù))是一樣的获黔,從這點(diǎn)不難看出痹雅,訪問者模式要求元素類的個(gè)數(shù)不能改變仰担。
  • 具體訪問者(ConcreteVisitor)角色:給出對(duì)每一個(gè)元素類訪問時(shí)所產(chǎn)生的具體行為。
  • 抽象元素(Element)角色:定義了一個(gè)接受訪問者的方法(accept)绩社,其意義是指摔蓝,每一個(gè)元素都要可以被訪問者訪問。
  • 具體元素(ConcreteElement)角色: 提供接受訪問方法的具體實(shí)現(xiàn)愉耙,而這個(gè)具體的實(shí)現(xiàn)贮尉,通常情況下是使用訪問者提供的訪問該元素類的方法。
  • 對(duì)象結(jié)構(gòu)(Object Structure)角色:定義當(dāng)中所提到的對(duì)象結(jié)構(gòu)朴沿,對(duì)象結(jié)構(gòu)是一個(gè)抽象表述绘盟,具體點(diǎn)可以理解為一個(gè)具有容器性質(zhì)或者復(fù)合對(duì)象特性的類,它會(huì)含有一組元素(Element)悯仙,并且可以迭代這些元素,供訪問者訪問吠卷。

實(shí)例

// 抽象元素角色(被訪問者)
// Animal.java
public interface Animal {

    // 接受訪問者訪問的功能
    void accept(Person person);
}

// 具體元素角色
// Cat.java
public class Cat implements Animal{
    @Override
    public void accept(Person person) {
        person.feed(this); // 訪問者給貓喂食
        System.out.println("貓吃飽了");
    }
}

// 具體元素角色
// Dog.java
public class Dogimplements Animal{
    @Override
    public void accept(Person person) {
        person.feed(this); // 訪問者給狗喂食
        System.out.println("狗吃飽了");
    }
}

// 抽象訪問者角色
// Person.java
public interface Person {
    // 喂食狗
    void feed(Cat cat);
    // 喂食貓
    void feed(Dog dog);
}

// 具體訪問者角色
// Owner.java
public class Owner implements Person{
    @Override
    public void feed(Cat cat) {
        System.out.println("主人喂食貓");
    }

    @Override
    public void feed(Dog dog) {
        System.out.println("主人喂食狗");
    }
}
// 具體訪問者角色
// Someone.java
public class Someone implements Person{
    @Override
    public void feed(Cat cat) {
        System.out.println("客人喂食貓");
    }

    @Override
    public void feed(Dog dog) {
        System.out.println("客人喂食狗");
    }
}

// 對(duì)象結(jié)構(gòu)角色
// Home.java
public class Home {

    // 聲明一個(gè)結(jié)合對(duì)象,用來存儲(chǔ)元素對(duì)象
    private List<Animal> nodeList = new ArrayList<>();

    // 添加元素功能
    public void add(Animal animal){
        nodeList.add(animal);
    }

    public void action(Person person){
        // 遍歷結(jié)合,獲取每一個(gè)元素,讓訪問者訪問每一個(gè)元素
        for(Animal animal:nodeList){
            animal.accept(person);
        }
    }
}

// Client.java
public class Client {
    public static void main(String[] args) {
        // 創(chuàng)建home對(duì)象
        Home home = new Home();
        // 添加元素到Home對(duì)象中
        home.add(new Dog());
        home.add(new Cat());

        // 創(chuàng)建主人對(duì)象
        Owner owner = new Owner();

        // 讓主人喂食寵物
        home.action(owner);
    }
}

Java中的分派

  • 變量被聲明時(shí)的類型叫做變量的靜態(tài)類型锡垄;
  • 變量所引用的對(duì)象的類型叫做對(duì)象的真實(shí)類型,也就是實(shí)際類型祭隔。
  • 例如Map map = new HashMap()中货岭,map變量的靜態(tài)類型是Map,實(shí)際類型是HashMap;
  • 根據(jù)對(duì)象的類型而對(duì)方法進(jìn)行的選擇就是分派(Dispatch),分派又分為兩種:靜態(tài)分派和動(dòng)態(tài)分派疾渴。
  • 靜態(tài)分派(Static Dispatch)發(fā)生在編譯時(shí)期千贯,分派根據(jù)靜態(tài)類型信息發(fā)生。靜態(tài)分派對(duì)于我們來說并不陌生搞坝,方法重載就是靜態(tài)分派搔谴;
  • 動(dòng)態(tài)分派(Dynamic Dispatch)發(fā)生在運(yùn)行時(shí)期,動(dòng)態(tài)分派動(dòng)態(tài)地置換掉了某個(gè)方法桩撮。Java通過對(duì)方法的重寫支持動(dòng)態(tài)分派敦第。

動(dòng)態(tài)分派

public class Animal {
    public void execute() {
        System.out.println("Animal");
    }
}

public class Dog extends Animal {
    @Override
    public void execute() {
        System.out.println("dog");
    }
}

public class Cat extends Animal {
     @Override
    public void execute() {
        System.out.println("cat");
    }
}

public class Client {
    public static void main(String[] args) {
        Animal a = new Dog();
        a.execute();
        
        Animal a1 = new Cat();
        a1.execute();
    }
}

靜態(tài)分派

public class Animal {
}

public class Dog extends Animal {
}

public class Cat extends Animal {
}

public class Execute {
    public void execute(Animal a) {
        System.out.println("Animal");
    }

    public void execute(Dog d) {
        System.out.println("dog");
    }

    public void execute(Cat c) {
        System.out.println("cat");
    }
}

public class Client {
    public static void main(String[] args) {
        Animal a = new Animal();
        Animal a1 = new Dog();
        Animal a2 = new Cat();

        Execute exe = new Execute();
        exe.execute(a);
        exe.execute(a1);
        exe.execute(a2);
    }
}
/*
執(zhí)行結(jié)果:
animal
animal
animal
*/
  • 重載方法的分派是根據(jù)靜態(tài)變量類型進(jìn)行的峰弹,這個(gè)分派過程在編譯階段就已經(jīng)完成。

雙分派技術(shù)

public class Animal {
    public void accept(Execute exe) {
        exe.execute(this);
    }
}

public class Dog extends Animal {
    public void accept(Execute exe) {
        exe.execute(this);
    }
}

public class Cat extends Animal {
    public void accept(Execute exe) {
        exe.execute(this);
    }
}

public class Execute {
    public void execute(Animal a) {
        System.out.println("animal");
    }

    public void execute(Dog d) {
        System.out.println("dog");
    }

    public void execute(Cat c) {
        System.out.println("cat");
    }
}

public class Client {
    public static void main(String[] args) {
        Animal a = new Animal();
        Animal d = new Dog();
        Animal c = new Cat();

        Execute exe = new Execute();
        a.accept(exe);
        d.accept(exe);
        c.accept(exe);
    }
}
  • 在該段代碼的執(zhí)行邏輯中芜果,發(fā)生了兩次分派行為鞠呈。
  • 首先在,a右钾、d蚁吝、c三個(gè)對(duì)象在調(diào)用accept()的時(shí)候,根據(jù)對(duì)于方法的重寫舀射,發(fā)生一次動(dòng)態(tài)分派窘茁,也就是執(zhí)行了對(duì)象的實(shí)際類型中的方法;
  • 其中后控,在每個(gè)方法的內(nèi)部庙曙,其調(diào)用了execute()方法,在execute()方法中浩淘,根據(jù)傳遞的this類型的不同捌朴,會(huì)靜態(tài)的分派到重載的方法中,發(fā)生了第二次分派张抄。
  • 雙分派的意圖就是在靜態(tài)的重載前面加上了動(dòng)態(tài)的重寫砂蔽,從而實(shí)現(xiàn)了動(dòng)態(tài)的重載。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末署惯,一起剝皮案震驚了整個(gè)濱河市左驾,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌极谊,老刑警劉巖诡右,帶你破解...
    沈念sama閱讀 211,348評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異轻猖,居然都是意外死亡帆吻,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,122評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門咙边,熙熙樓的掌柜王于貴愁眉苦臉地迎上來猜煮,“玉大人,你說我怎么就攤上這事败许⊥醮” “怎么了?”我有些...
    開封第一講書人閱讀 156,936評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵市殷,是天一觀的道長愕撰。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么盟戏? 我笑而不...
    開封第一講書人閱讀 56,427評(píng)論 1 283
  • 正文 為了忘掉前任绪妹,我火速辦了婚禮,結(jié)果婚禮上柿究,老公的妹妹穿的比我還像新娘邮旷。我一直安慰自己,他們只是感情好蝇摸,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,467評(píng)論 6 385
  • 文/花漫 我一把揭開白布婶肩。 她就那樣靜靜地躺著,像睡著了一般貌夕。 火紅的嫁衣襯著肌膚如雪律歼。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,785評(píng)論 1 290
  • 那天啡专,我揣著相機(jī)與錄音险毁,去河邊找鬼。 笑死们童,一個(gè)胖子當(dāng)著我的面吹牛畔况,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播慧库,決...
    沈念sama閱讀 38,931評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼跷跪,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了齐板?” 一聲冷哼從身側(cè)響起吵瞻,我...
    開封第一講書人閱讀 37,696評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎甘磨,沒想到半個(gè)月后橡羞,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,141評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡济舆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,483評(píng)論 2 327
  • 正文 我和宋清朗相戀三年尉姨,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片吗冤。...
    茶點(diǎn)故事閱讀 38,625評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖九府,靈堂內(nèi)的尸體忽然破棺而出椎瘟,到底是詐尸還是另有隱情,我是刑警寧澤侄旬,帶...
    沈念sama閱讀 34,291評(píng)論 4 329
  • 正文 年R本政府宣布肺蔚,位于F島的核電站,受9級(jí)特大地震影響儡羔,放射性物質(zhì)發(fā)生泄漏宣羊。R本人自食惡果不足惜璧诵,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,892評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望仇冯。 院中可真熱鬧之宿,春花似錦、人聲如沸苛坚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽泼舱。三九已至等缀,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間娇昙,已是汗流浹背尺迂。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留冒掌,地道東北人噪裕。 一個(gè)月前我還...
    沈念sama閱讀 46,324評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像宋渔,于是被迫代替她去往敵國和親州疾。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,492評(píng)論 2 348

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

  • 定義 訪問者模式是對(duì)象的行為模式皇拣。訪問者模式的目的是封裝一些施加于某種數(shù)據(jù)結(jié)構(gòu)元素之上的操作严蓖。一旦這些操作需要修改...
    步積閱讀 1,220評(píng)論 0 3
  • 目錄 本文的結(jié)構(gòu)如下: 引言 什么是訪問者模式 模式的結(jié)構(gòu) 典型代碼 訪問者模式中的偽動(dòng)態(tài)雙分派 代碼示例 訪問者...
    w1992wishes閱讀 860評(píng)論 0 6
  • 一、簡(jiǎn)述 訪問者模式是一種將數(shù)據(jù)操作和數(shù)據(jù)結(jié)構(gòu)分離的設(shè)計(jì)模式氧急,是23種設(shè)計(jì)模式中非常復(fù)雜的一種颗胡,而且使用頻率并不高...
    MrTrying閱讀 1,196評(píng)論 1 9
  • 久違的晴天,家長會(huì)吩坝。 家長大會(huì)開好到教室時(shí)毒姨,離放學(xué)已經(jīng)沒多少時(shí)間了。班主任說已經(jīng)安排了三個(gè)家長分享經(jīng)驗(yàn)钉寝。 放學(xué)鈴聲...
    飄雪兒5閱讀 7,513評(píng)論 16 22
  • 今天感恩節(jié)哎弧呐,感謝一直在我身邊的親朋好友。感恩相遇嵌纲!感恩不離不棄俘枫。 中午開了第一次的黨會(huì),身份的轉(zhuǎn)變要...
    迷月閃星情閱讀 10,559評(píng)論 0 11