補-設(shè)計模式之訪問者模式(十三)

??訪問者模式在23種設(shè)計模式算是復(fù)雜的,因此在解釋定義前,先以實際的例子代入一下磨德,覺得理解起來會更好一些。

場景:很多人都有養(yǎng)寵物的習(xí)慣吆视,這里就以此為例

訪問者角色:給寵物喂食的人

具體訪問者角色:主人典挑、其他人

抽象元素角色:動物抽象類

具體元素角色:寵物狗、寵物貓

結(jié)構(gòu)對象角色:主人家

結(jié)構(gòu)圖
  • 創(chuàng)建抽象訪問者接口
interface Person {

     void feed(Cat cat);

     void feed(Dog dog);
}
  • 創(chuàng)建不同的具體訪問者角色 -- 主人/其他人啦吧,同時實現(xiàn)Person接口
class Owner implements Person {

@Override
public void feed(Cat cat) {
    System.out.println("主人喂食貓");
}

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

class Someone implements Person {

@Override
public void feed(Cat cat) {
    System.out.println("其他人喂食貓");
}

@Override
public void feed(Dog dog) {
    System.out.println("其他人喂食狗");
}
}
  • 創(chuàng)建 抽象節(jié)點 -- 寵物
interface Animal {
      void accept(Person person);
}
  • 創(chuàng)建實現(xiàn)Animal接口的 具體節(jié)點(元素)
/**
 * 具體節(jié)點(元素)角色 -- 寵物狗
 */
class Dog implements Animal {

@Override
public void accept(Person person) {
    person.feed(this);
    System.out.println("好好吃您觉,汪汪汪!J谧摇琳水!");
}
}


/**
 * 具體節(jié)點(元素)角色 -- 寵物貓
 */
class Cat implements Animal {

@Override
public void accept(Person person) {
    person.feed(this);
    System.out.println("好好吃,喵喵喵0愣选T谛ⅰ!");
}
}
  • 創(chuàng)建結(jié)構(gòu)對象角色
class Home {
private List<Animal> nodeList = new ArrayList<>();

void action(Person person) {
    for (Animal node : nodeList) {
        node.accept(person);
    }
}

/**
 * 添加操作
 *
 * @param animal 動物
 */
void add(Animal animal) {
    nodeList.add(animal);
}
}
  • 創(chuàng)建客戶端淮摔,用于測試
public class Client {

public static void main(String[] args) {
    Home home = new Home();
    home.add(new Dog());
    home.add(new Cat());

    Owner owner = new Owner();
    home.action(owner);

    Someone someone = new Someone();
    home.action(someone);
}

}

  • 運行結(jié)果
主人喂食狗
好好吃私沮,汪汪汪!:统取仔燕!
主人喂食貓
好好吃造垛,喵喵喵!N蟆五辽!
其他人喂食狗
好好吃,汪汪汪M馑 1计辍!
其他人喂食貓
好好吃吁讨,喵喵喵!B屠省建丧!

什么訪問者模式?

??訪問者模式(Visitor)表示一個作用于某對象結(jié)構(gòu)中的各元素的操作波势。它使你可以在不改變各元素的類的前提下定義作用于這些元素的新操作翎朱。訪問者模式是一種對象行為模式。

訪問模式角色

  • Visitor 抽象訪問者

??為該對象結(jié)構(gòu)中的ConcreteElement的每一個類聲明的一個操作尺铣。

  • ConcreteVisitor 具體訪問者

??實現(xiàn)Visitor申明的每一個操作拴曲,每一個操作實現(xiàn)算法的一部分。

  • Element 抽象元素

??它定義了一個接受訪問者(accept)的方法凛忿,其意義是指澈灼,每一個元素都要可以被訪問者訪問。

  • ConcreteElement 具體元素

??它提供接受訪問方法的具體實現(xiàn)店溢,而這個具體的實現(xiàn)叁熔,通常情況下是使用訪問者提供的訪問該元素類的方法。

  • ObjectStructure 對象結(jié)構(gòu)角色

??對象結(jié)構(gòu)是一個抽象表述床牧,具體點可以理解為一個具有容器性質(zhì)或者復(fù)合對象特性的類荣回,它會含有一組元素(Element),并且可以迭代這些元素戈咳,供訪問者訪問心软。

訪問模式優(yōu)缺點

優(yōu)點:

?新增訪問操作變得更加簡單。

?能夠使得用戶在不修改現(xiàn)有類的層次結(jié)構(gòu)下著蛙,定義該類層次結(jié)構(gòu)的操作删铃。

?將有關(guān)元素對象的訪問行為集中到一個訪問者對象中,而不是分散搞一個個的元素類中册踩。

缺點:

?增加新的元素類很困難泳姐。在訪問者模式中,每增加一個新的元素類都意味著要在抽象訪問者角色中增加一個新的抽象操作暂吉,并在每一個具體訪問者類中增加相應(yīng)的具體操作胖秒,違背了“開閉原則”的要求缎患。

?破壞封裝。當(dāng)采用訪問者模式的時候阎肝,就會打破組合類的封裝挤渔。

訪問者模式結(jié)構(gòu)圖

訪問者模式基本代碼

  • 抽象訪問者
public abstract class Visitor {

public abstract void visitConcreteElementA(ConcreteElementA concreteElementA);

public abstract void visitConcreteElementB(ConcreteElementB concreteElementB);
}
  • 具體訪問者
public class ConcreteVisitor1 extends Visitor {
@Override
public void visitConcreteElementA(ConcreteElementA concreteElementA) {
    System.out.println("ConcreteVisitor1:"+concreteElementA.operationA());
}

@Override
public void visitConcreteElementB(ConcreteElementB concreteElementB) {
    System.out.println("ConcreteVisitor1:"+concreteElementB.operationB());
}
}

public class ConcreteVisitor2 extends Visitor {
@Override
public void visitConcreteElementA(ConcreteElementA concreteElementA) {
    System.out.println("ConcreteVisitor2:"+concreteElementA.operationA());
}

@Override
public void visitConcreteElementB(ConcreteElementB concreteElementB) {
    System.out.println("ConcreteVisitor2:"+concreteElementB.operationB());
}
}
  • 抽象元素
public abstract class Element {

       public abstract void accept(Visitor visitor);
}
  • 具體元素
public class ConcreteElementA extends Element {
@Override
public void accept(Visitor visitor) {
    visitor.visitConcreteElementA(this);
}

public String operationA() {
    return "ConcreteElementA";
}
}

public class ConcreteElementB extends  Element {

@Override
public void accept(Visitor visitor) {
    visitor.visitConcreteElementB(this);
}

public String operationB() {
    return "ConcreteElementB";
}
}
  • 對象結(jié)構(gòu)角色
public class ObjectStructure {

private List<Element> elments = new LinkedList<Element>();

// 新增
public void attach(Element element) {
    elments.add(element);
}
// 刪除
public void detach(Element element) {
    elments.remove(element);
}

public  void accept(Visitor visitor) {
    for (Element elment:elments ) {
        elment.accept(visitor);
    }
}
}
  • 測試類
public class Test {

public static void main(String[]args) {
    ObjectStructure o = new ObjectStructure();
    o.attach(new ConcreteElementA());
    o.attach(new ConcreteElementB());

    ConcreteVisitor1 concreteVisitor1 = new ConcreteVisitor1();
    ConcreteVisitor2 concreteVisitor2 = new ConcreteVisitor2();
    o.accept(concreteVisitor1);
    o.accept(concreteVisitor2);
}
}
  • 運行結(jié)果
ConcreteVisitor1:ConcreteElementA
ConcreteVisitor1:ConcreteElementB
ConcreteVisitor2:ConcreteElementA
ConcreteVisitor2:ConcreteElementB

小結(jié)

??GoF四人中的一個作者說過:大多時候你并不需要訪問者模式,但一旦你需要訪問者模式時风题,那就是真的需要它了判导。事實上我們很難找到數(shù)據(jù)結(jié)構(gòu)不變化的情況,所以用訪問者模式的機會也就不太多了沛硅。


?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末眼刃,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子摇肌,更是在濱河造成了極大的恐慌擂红,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件围小,死亡現(xiàn)場離奇詭異昵骤,居然都是意外死亡,警方通過查閱死者的電腦和手機肯适,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進(jìn)店門变秦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人框舔,你說我怎么就攤上這事蹦玫。” “怎么了刘绣?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵钳垮,是天一觀的道長。 經(jīng)常有香客問我额港,道長饺窿,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任移斩,我火速辦了婚禮肚医,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘向瓷。我一直安慰自己肠套,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布猖任。 她就那樣靜靜地躺著你稚,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上刁赖,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天搁痛,我揣著相機與錄音,去河邊找鬼宇弛。 笑死鸡典,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的枪芒。 我是一名探鬼主播彻况,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼舅踪!你這毒婦竟也來了纽甘?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤抽碌,失蹤者是張志新(化名)和其女友劉穎贷腕,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體咬展,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年瞒斩,在試婚紗的時候發(fā)現(xiàn)自己被綠了破婆。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡胸囱,死狀恐怖祷舀,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情烹笔,我是刑警寧澤裳扯,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站谤职,受9級特大地震影響饰豺,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜允蜈,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一冤吨、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧饶套,春花似錦漩蟆、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春捺癞,著一層夾襖步出監(jiān)牢的瞬間夷蚊,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工翘簇, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留撬码,地道東北人。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓版保,卻偏偏與公主長得像呜笑,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子彻犁,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,713評論 2 354

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