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

本文源碼:GitHub·點這裏 || GitEE·點這裏java

1、生活場景

一、場景描述

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

二、場景圖解

三、代碼實現

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);
        }
    }
}

2、訪問者模式

一、基礎概念

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

二、模式圖解

三、核心角色

  • 抽象訪問者角色

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

  • 具體訪問者角色

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

  • 抽象節點角色

聲明接受操做,接受訪問者對象做爲參數。編程

  • 具體節點角色

實現抽象節點所規定的具體操做。網絡

  • 結構對象角色

能枚舉結構中的全部元素,能夠提供一個高層的接口,用來容許訪問者對象訪問每個元素。數據結構

四、源碼實現

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);
        }
    }
}

3、Spring框架應用

一、Bean結構的訪問

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

二、核心代碼塊

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());
        }
    }
}

4、模式總結

一、優勢描述ide

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

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

二、缺點描述

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

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

5、源代碼地址

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

相關文章
相關標籤/搜索