設(shè)計模式-訪問者模式(二十)

  • 目的是:

封裝一些施加于某種數(shù)據(jù)結(jié)構(gòu)元素之上的操作,一旦這些操作改變,接受這個操作的數(shù)據(jù)結(jié)構(gòu)則可以保持不變

何時使用:需要對一個對象結(jié)構(gòu)中的對象進行很多不同的并且不相關(guān)的操作,而需要避免讓這些操作"污染"這些對象的類,使用訪問者模式將這些封裝到類中

Problem:如何針對保存有不同類型對象的聚集采取某種操作?
用if?

image.png

訪問者模式適用于 數(shù)據(jù)結(jié)構(gòu)不確定的情況,它把數(shù)據(jù)結(jié)構(gòu)和操作之間的耦合解脫開。

  • 使用場景: 1、對象結(jié)構(gòu)中對象對應(yīng)的類很少改變(也就是Node很少改變),但經(jīng)常需要在此對象結(jié)構(gòu)上定義新的操作(也就是經(jīng)常要增加Visitor)

  • 上類圖:


    訪問者角色.png
  • 優(yōu)點:
    將有關(guān)的行為集中到一個訪問者對象中,而不是分散到一個個節(jié)點類中,行為集中了,相關(guān)的操作狀態(tài)(類似屬性)也積累在自己的內(nèi)部,而不是分散到很多對象中,這是有利于維護的.

  • 缺點:
    如果要增加一個新的節(jié)點都要在抽象訪問者角色中增加一個新的抽象操作.

  • 代碼示例:

  1. 定義一個訪問者訪問的接口類,抽象節(jié)點角色
/**
 * FileName :ComputerPart
 * Author :zengzhijun
 * Date : 2018/5/28 15:34
 * Description:
 */
package com.byedbl.visitor.sample2.entity;

import com.byedbl.visitor.sample2.visitor.ComputerPartVisitor;

public interface ComputerPart {
    public void accept(ComputerPartVisitor computerPartVisitor);
}

  1. 實現(xiàn)4個具體節(jié)點
/**
 * FileName :Keyboard
 * Author :zengzhijun
 * Date : 2018/5/28 15:34
 * Description:
 */
package com.byedbl.visitor.sample2.entity;

import com.byedbl.visitor.sample2.visitor.ComputerPartVisitor;

public class Keyboard  implements ComputerPart {

    @Override
    public void accept(ComputerPartVisitor computerPartVisitor) {
        computerPartVisitor.visit(this);
    }
}
/**
 * FileName :Monitor
 * Author :zengzhijun
 * Date : 2018/5/28 15:35
 * Description:
 */
package com.byedbl.visitor.sample2.entity;

import com.byedbl.visitor.sample2.visitor.ComputerPartVisitor;

public class Monitor  implements ComputerPart {

    @Override
    public void accept(ComputerPartVisitor computerPartVisitor) {
        computerPartVisitor.visit(this);
    }
}

/**
 * FileName :Mouse
 * Author :zengzhijun
 * Date : 2018/5/28 15:35
 * Description:
 */
package com.byedbl.visitor.sample2.entity;

import com.byedbl.visitor.sample2.visitor.ComputerPartVisitor;

public class Mouse  implements ComputerPart {

    @Override
    public void accept(ComputerPartVisitor computerPartVisitor) {
        computerPartVisitor.visit(this);
    }
}
/**
 * FileName :Computer
 * Author :zengzhijun
 * Date : 2018/5/28 15:35
 * Description:
 */
package com.byedbl.visitor.sample2.entity;

import com.byedbl.visitor.sample2.visitor.ComputerPartVisitor;

public class Computer implements ComputerPart {

    ComputerPart[] parts;

    public Computer(){
        parts = new ComputerPart[] {new Mouse(), new Keyboard(), new Monitor()};
    }


    @Override
    public void accept(ComputerPartVisitor computerPartVisitor) {
        for (int i = 0; i < parts.length; i++) {
            parts[i].accept(computerPartVisitor);
        }
        computerPartVisitor.visit(this);
    }
}

  1. 定義訪問者抽象接口
/**
 * FileName :ComputerPartVisitor
 * Author :zengzhijun
 * Date : 2018/5/28 15:36
 * Description:
 */
package com.byedbl.visitor.sample2.visitor;

import com.byedbl.visitor.sample2.entity.Computer;
import com.byedbl.visitor.sample2.entity.Keyboard;
import com.byedbl.visitor.sample2.entity.Monitor;
import com.byedbl.visitor.sample2.entity.Mouse;

public interface ComputerPartVisitor {
    public void visit(Computer computer);
    public void visit(Mouse mouse);
    public void visit(Keyboard keyboard);
    public void visit(Monitor monitor);
}

  1. 實現(xiàn)訪問者接口
/**
 * FileName :ComputerPartDisplayVisitor
 * Author :zengzhijun
 * Date : 2018/5/28 15:36
 * Description:
 */
package com.byedbl.visitor.sample2.visitor;

import com.byedbl.visitor.sample2.entity.Computer;
import com.byedbl.visitor.sample2.entity.Keyboard;
import com.byedbl.visitor.sample2.entity.Monitor;
import com.byedbl.visitor.sample2.entity.Mouse;

public class ComputerPartDisplayVisitor implements ComputerPartVisitor {

    @Override
    public void visit(Computer computer) {
        System.out.println("Displaying Computer.");
    }

    @Override
    public void visit(Mouse mouse) {
        System.out.println("Displaying Mouse.");
    }

    @Override
    public void visit(Keyboard keyboard) {
        System.out.println("Displaying Keyboard.");
    }

    @Override
    public void visit(Monitor monitor) {
        System.out.println("Displaying Monitor.");
    }
}

  1. 客戶端用法
/**
 * FileName :VisitorPatternDemo
 * Author :zengzhijun
 * Date : 2018/5/28 15:36
 * Description:
 */
package com.byedbl.visitor.sample2;

import com.byedbl.visitor.sample2.entity.Computer;
import com.byedbl.visitor.sample2.entity.ComputerPart;
import com.byedbl.visitor.sample2.entity.Mouse;
import com.byedbl.visitor.sample2.visitor.ComputerPartDisplayVisitor;

/**
 *
 * <pre>
 * 備受爭議的訪問者模式
 * 因為增加一個Node節(jié)點就要在Visitor節(jié)點中(這里是 ComputerPartVisitor)增加一個方法支持它
 * 如果已經(jīng)實現(xiàn)了很多Visitor那不是很坑爹?當(dāng)然在java8里面可以加一個默認的方法了,情況可能好一點
 * 但是還是不能掩蓋其違反了開閉原則
 *
 * 但是作為實用主義來講,只要管用,理論就可以先一邊呆著去...
 * 畢竟像中國的代碼,if else if 幾百行 也不是沒見過的
 *
 * @author : zengzhijun
 * @date : 2018/5/28 15:51
 **/
public class VisitorPatternDemo {

    public static void main(String[] args) {

        ComputerPart computer = new Computer();
        computer.accept(new ComputerPartDisplayVisitor());
        System.out.println("--------------");
        ComputerPart computerPart = new Mouse();
        computerPart.accept(new ComputerPartDisplayVisitor());
    }
}

這個例子很形象,電腦組件就這幾個,但是不同的人用來干不同的事,也就是滿足對象結(jié)構(gòu)中對象對應(yīng)的類很少改變(也就是Node很少改變),但經(jīng)常需要在此對象結(jié)構(gòu)上定義新的操作(也就是經(jīng)常要增加Visitor)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容