Java描述設計模式(23):訪問者模式

本文源碼: ||

一、生活場景

1、場景描述

電競是遊戲比賽達到“競技”層面的體育項目。利用电子設備作為運動器械進行的、人與人之間的智力對抗運動。通過電競,可以提高人的反應能力、協調能力、團隊精神等。但是不同人群的對電競的持有的觀念不一樣,有的人認為電競就是沉迷網絡,持反對態度,而有的人就比較贊同。下面基於訪問者模式來描述該場景。

2、場景圖解

3、代碼實現

public class C01_InScene {
    public static void main(String[] args) {
        DataSet dataSet = new DataSet() ;
        dataSet.addCrowd(new Youth());
        dataSet.addCrowd(new MiddleAge());
        CrowdView crowdView = new Against() ;
        dataSet.display(crowdView);
        crowdView = new Approve() ;
        dataSet.display(crowdView);
    }
}
/**
 * 雙分派,不同人群管理
 */
abstract class Crowd {
    abstract void accept(CrowdView action);
}
class Youth extends Crowd {
    @Override
    public void accept(CrowdView view) {
        view.getYouthView(this);
    }
}
class MiddleAge extends Crowd {
    @Override
    public void accept(CrowdView view) {
        view.getMiddleAgeView (this);
    }
}
/**
 * 不同人群觀念的管理
 */
abstract class CrowdView {
    // 青年人觀念
    abstract void getYouthView (Youth youth);
    // 中年人觀念
    abstract void getMiddleAgeView (MiddleAge middleAge);
}
class Approve extends CrowdView {
    @Override
    public void getYouthView(Youth youth) {
        System.out.println("青年人贊同電競");
    }
    @Override
    public void getMiddleAgeView(MiddleAge middleAge) {
        System.out.println("中年人贊同電競");
    }
}
class Against extends CrowdView {
    @Override
    public void getYouthView(Youth youth) {
        System.out.println("青年人反對電競");
    }
    @Override
    public void getMiddleAgeView(MiddleAge middleAge) {
        System.out.println("中年人反對電競");
    }
}
/**
 * 提供一個數據集合
 */
class DataSet {
    private List<Crowd> crowdList = new ArrayList<>();
    public void addCrowd (Crowd crowd) {
        crowdList.add(crowd);
    }
    public void display(CrowdView crowdView) {
        for(Crowd crowd : crowdList) {
            crowd.accept(crowdView);
        }
    }
}

二、訪問者模式

1、基礎概念

訪問者模式是對象的行為模式,把作用於數據結構的各元素的操作封裝,操作之間沒有關聯。可以在不改變數據結構的前提下定義作用於這些元素的不同的操作。主要將數據結構與數據操作分離,解決數據結構和操作耦合問題核心原理:被訪問的類裏面加對外提供接待訪問者的接口。

2、模式圖解

3、核心角色

  • 抽象訪問者角色

聲明多個方法操作,具體訪問者角色需要實現的接口。

  • 具體訪問者角色

實現抽象訪問者所聲明的接口,就是各個訪問操作。

  • 抽象節點角色

聲明接受操作,接受訪問者對象作為參數。

  • 具體節點角色

實現抽象節點所規定的具體操作。

  • 結構對象角色

能枚舉結構中的所有元素,可以提供一個高層的接口,用來允許訪問者對象訪問每一個元素。

4、源碼實現

public class C02_Visitor {
    public static void main(String[] args) {
        ObjectStructure obs = new ObjectStructure();
        obs.add(new NodeA());
        obs.add(new NodeB());
        Visitor visitor = new VisitorA();
        obs.doAccept(visitor);
    }
}
/**
 * 抽象訪問者角色
 */
interface Visitor {
    /**
     * NodeA的訪問操作
     */
    void visit(NodeA node);
    /**
     * NodeB的訪問操作
     */
    void visit(NodeB node);
}
/**
 * 具體訪問者角色
 */
class VisitorA implements Visitor {
    @Override
    public void visit(NodeA node) {
        node.operationA() ;
    }
    @Override
    public void visit(NodeB node) {
        node.operationB() ;
    }
}
class VisitorB implements Visitor {
    @Override
    public void visit(NodeA node) {
        node.operationA() ;
    }
    @Override
    public void visit(NodeB node) {
        node.operationB() ;
    }
}
/**
 * 抽象節點角色
 */
abstract class Node {
    /**
     * 接收訪問者
     */
    abstract void accept(Visitor visitor);
}
/**
 * 具體節點角色
 */
class NodeA extends Node{
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
    public void operationA(){
        System.out.println("NodeA.operationA");
    }
}
class NodeB extends Node{
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
    public void operationB(){
        System.out.println("NodeB.operationB");
    }
}
/**
 * 結構對象角色類
 */
class ObjectStructure {
    private List<Node> nodes = new ArrayList<>();
    public void detach(Node node) {
        nodes.remove(node);
    }
    public void add(Node node){
        nodes.add(node);
    }
    public void doAccept(Visitor visitor){
        for(Node node : nodes) {
            node.accept(visitor);
        }
    }
}

三、Spring框架應用

1、Bean結構的訪問

BeanDefinitionVisitor類,遍歷bean的各個屬性;接口 BeanDefinition,定義Bean的各樣信息,比如屬性值、構造方法、參數等等。這裏封裝操作bean結構的相關方法,但卻沒有改變bean的結構。

2、核心代碼塊

public class BeanDefinitionVisitor {
    public void visitBeanDefinition(BeanDefinition beanDefinition) {
        this.visitParentName(beanDefinition);
        this.visitBeanClassName(beanDefinition);
        this.visitFactoryBeanName(beanDefinition);
        this.visitFactoryMethodName(beanDefinition);
        this.visitScope(beanDefinition);
        if (beanDefinition.hasPropertyValues()) {
            this.visitPropertyValues(beanDefinition.getPropertyValues());
        }
        if (beanDefinition.hasConstructorArgumentValues()) {
            ConstructorArgumentValues cas = beanDefinition.getConstructorArgumentValues();
            this.visitIndexedArgumentValues(cas.getIndexedArgumentValues());
            this.visitGenericArgumentValues(cas.getGenericArgumentValues());
        }
    }
}

四、模式總結

1、優點描述

(1) 訪問者模式符合單一職責原則、使程序具有良好的擴展性、靈活性;

(2) 訪問者模式適用與攔截器與過濾器等常見功能,數據結構相對穩定的場景;

2、缺點描述

(1) 訪問者關注其他類的內部細節,依賴性強,違反迪米特法則,這樣導致具體元素更新麻煩;

(2) 訪問者依賴具體元素,不是抽象元素,面向細節編程,違背依賴倒轉原則;

五、源代碼地址

GitHub·地址
https://github.com/cicadasmile/model-arithmetic-parent
GitEE·地址
https://gitee.com/cicadasmile/model-arithmetic-parent

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選