訪問者模式的使用

一、模式介紹

訪問者模式通常包含如下幾個角色:

  • 抽象元素,定義元素接受訪問者訪問的方法;
  • 具體元素,提供接受訪問者訪問的具體實現(xiàn),以及自身的一些操作;
  • 抽象訪問者,定義多個visit方法用來訪問每一個具體元素,理論上visit方法個數(shù)等于具體元素個數(shù);因此要求該模式使用場景是元素穩(wěn)定不變的。
  • 具體訪問者,實現(xiàn)對具體元素操作的訪問;
  • 結構對象,維護具體元素的集合,提供方法接受具體訪問者對集合中的所有元素進行訪問;

通用的實現(xiàn)代碼如下:

/**
 * 抽象元素
 * 定義接受訪問者訪問的方法
 * 所有具體元素都支持被訪問者訪問
 */
public interface IElement {
    void accept(IVisitor visitor);
}
/**
 * 具體元素A
 */
@Slf4j
public class ConcreteElementA implements IElement{
    @Override
    public void accept(IVisitor visitor) {
        // 訪問者進行訪問
        visitor.visit(this);
    }

    public void operation(){
        log.info("ConcreteElementA operation");
    }
}
/**
 * 具體元素B
 */
@Slf4j
public class ConcreteElementB implements IElement{
    @Override
    public void accept(IVisitor visitor) {
        // 訪問者進行訪問
        visitor.visit(this);
    }

    public void operation(){
        log.info("ConcreteElementB operation");
    }
}
/**
 * 抽象訪問者
 */
public interface IVisitor {
    /**
     * 定義visit方法訪問每一個具體的元素
     * 理論上visit方法個數(shù)和具體元素的個數(shù)是相等的
     * @param element
     */
    void visit(ConcreteElementA element);
    void visit(ConcreteElementB element);
}
/**
 * 具體訪問者,實現(xiàn)對具體元素的訪問操作
 */
public class ConcreteVisitor implements IVisitor{
    @Override
    public void visit(ConcreteElementA element) {
        element.operation();
    }

    @Override
    public void visit(ConcreteElementB element) {
        element.operation();
    }
}
public class ObjectStructure {
    private List<IElement> list = new ArrayList<>();

    /**
     * 需要被訪問的具體元素初始化時都裝入集合中
     */
    {
        this.list.add(new ConcreteElementA());
        this.list.add(new ConcreteElementB());
    }

    /**
     * 接待某個具體的訪問者
     * @param visitor
     */
    public void accept(IVisitor visitor){
        // 帶訪問者依次參觀具體元素
        for (IElement element : this.list) {
            element.accept(visitor);
        }
    }
}
@Slf4j
public class Main {
    public static void main(String[] args) {
        ObjectStructure collection = new ObjectStructure();
        IVisitor jack = new ConcreteVisitor();
        // 接待jack這個訪問者
        collection.accept(jack);
    }
}

我們將如上的案例來做一個實際場景的類比:

  • ObjectStructure相當于一個家族的管家,具體元素類相當于每個房間里面的主人,家族里面主人的個數(shù)肯定是固定的,然后訪問者來家族進行訪問的時候,由管家進行接待accept(visitor);
  • 然后管家?guī)ьI訪問者依次去每個房間拜訪主人element.accept(visitor);
  • 每個主人需要同意accept(visitor)訪問者訪問后,訪問者才可以進行對當前主人的訪問visitor.visit(this);
  • 然后這個主人才和訪問者進行交流,展示自己operation

在這樣的設計模式中,任何訪問者想來拜訪,只要讓管家去接待一下即可,每個房間的主人們則完全不用操心,只需要固定地接受拜訪并展示自己即可,對訪問者的擴展十分方便。與此同時,倘若每個房間的主人有多項技能的話(唱歌、跳舞、吟詩、作畫......),訪問者可以自己定義想拜訪主人都需要為自己展示什么才能,只要過了管家這一關即可,因為必須要管家給安排。

二、使用場景

  • JDK的NIO中的FileVisitor接口;
  • Spring中的BeanDefinitionVisitor類;

三、模式總結

3.1 優(yōu)點

  • 解耦了數(shù)據結構和數(shù)據操作;
  • 可以很方便地擴展訪問者角色,實現(xiàn)對不同數(shù)據集的不同操作,擴展性良好;
  • 元素具體類型可以是多樣的,訪問者均可操作;
  • 各個角色職責分離,符合單一職責原則;

3.2 缺點

  • 無法靈活增加元素類型,否則就得頻繁改動訪問者,違反了開閉原則;
  • 元素行為增刪困難,需要改動訪問者的調用行為,違反了開閉原則;
  • 訪問者直接耦合了具體元素類,而沒有以來抽象,違背了依賴倒置原則;
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容