cola架构:cola源码中访问者模式应用浅析

目录

1.访问者模式简介

2.cola访问者模式应用

[2.1 cola被访问者类图](#2.1 cola被访问者类图)

[2.2 cola访问者类图](#2.2 cola访问者类图)


我们知道,如果一个对象结构包含很多类型的对象,希望对这些对象实施一些依赖其具体类型的操作,但又避免让这些操作"污染"这些对象的类,也不希望在增加新操作时修改这些类,那么可以使用访问者设计模式;它使得我们可以将相关的访问操作集中起来定义在访问者类中,将对象本身与对象的访问操作分离。

在cola框架中,针对状态机(StateMachine)和状态(State)就应用了访问者模式,下面进行具体分析;

附:

cola状态机源码解析见上篇文章:cola架构:有限状态机(FSM)源码分析

1.访问者模式简介

访问者(Visitor)模式:将作用于某种数据结构中的各元素的操作分离出来封装成独立的类,使其在不改变数据结构的前提下可以添加作用于这些元素的新的操作,为数据结构中的每个元素提供多种访问方式。

访问者模式包含的类/接口如下:

  • 抽象访问者(Visitor):定义一个访问具体元素的接口,为每个具体元素类对应一个访问操作 visit() ,该操作中的参数类型标识了被访问的具体元素。
  • 具体访问者(ConcreteVisitor):实现抽象访问者角色中声明的各个访问操作,确定访问者访问一个元素时该做什么。
  • 抽象元素(Element):声明一个包含接受操作 accept() 的接口,被接受的访问者对象作为 accept() 方法的参数。
  • 具体元素(ConcreteElement):实现抽象元素角色提供的 accept() 操作,其方法体通常都是 visitor.visit(this) ,另外具体元素中可能还包含本身业务逻辑的相关操作

  • 对象结构(Object Structure):是一个包含元素角色的容器,提供让访问者对象遍历容器中的所有元素的方法,通常由 List、Set、Map 等聚合类实现。

相关类图及引用结构如下:

2.cola访问者模式应用

2.1 cola被访问者类图

cola被访问者类图如下,包含被访问者State和StateMachine:

Visitable接口定义了accept接口,接受Visitor参数对象:

java 复制代码
public interface Visitable {
    String accept(final Visitor visitor);
}

StateImpl实现accept接口如下:

java 复制代码
public class StateImpl<S,E,C> implements State<S,E,C> {

    @Override
    public String accept(Visitor visitor) {
        String entry = visitor.visitOnEntry(this);
        String exit = visitor.visitOnExit(this);
        return entry + exit;
    }
}

StateMachineImpl实现accept接口如下:

java 复制代码
public class StateMachineImpl<S, E, C> implements StateMachine<S, E, C> {

    @Override
    public String accept(Visitor visitor) {
        StringBuilder sb = new StringBuilder();
        sb.append(visitor.visitOnEntry(this));
        for (State state : stateMap.values()) {
            sb.append(state.accept(visitor));
        }
        sb.append(visitor.visitOnExit(this));
        return sb.toString();
    }
}

实现逻辑里,通过简单调用访问者类的visit方法完成对被访问者的访问。

2.2 cola访问者类图

cola访问者包含PlantUMLVisitor和SysOutVisitor,类图如下:

Visitor接口约定了分别针对State和StateMachine的visit接口方法:

java 复制代码
/**
 * Visitor
 *
 * @author Frank Zhang
 * @date 2020-02-08 8:41 PM
 */
public interface Visitor {

    char LF = '\n';

    /**
     * @param visitable the element to be visited.
     * @return
     */
    String visitOnEntry(StateMachine<?, ?, ?> visitable);

    /**
     * @param visitable the element to be visited.
     * @return
     */
    String visitOnExit(StateMachine<?, ?, ?> visitable);

    /**
     * @param visitable the element to be visited.
     * @return
     */
    String visitOnEntry(State<?, ?, ?> visitable);

    /**
     * @param visitable the element to be visited.
     * @return
     */
    String visitOnExit(State<?, ?, ?> visitable);
}
  • PlantUMLVisitor实现了针对State和StateMachine的plantuml方式的输出格式;
  • SysOutVisitor实现了对State和StateMachine简单日志输出;
java 复制代码
/**
 * PlantUMLVisitor
 *
 * @author Frank Zhang
 * @date 2020-02-09 7:47 PM
 */
public class PlantUMLVisitor implements Visitor {

    /**
     * Since the state machine is stateless, there is no initial state.
     *
     * You have to add "[*] -> initialState" to mark it as a state machine diagram.
     * otherwise it will be recognized as a sequence diagram.
     *
     * @param visitable the element to be visited.
     * @return
     */
    @Override
    public String visitOnEntry(StateMachine<?, ?, ?> visitable) {
        return "@startuml" + LF;
    }

    @Override
    public String visitOnExit(StateMachine<?, ?, ?> visitable) {
        return "@enduml";
    }

    @Override
    public String visitOnEntry(State<?, ?, ?> state) {
        StringBuilder sb = new StringBuilder();
        for(Transition transition: state.getAllTransitions()){
            sb.append(transition.getSource().getId())
                    .append(" --> ")
                    .append(transition.getTarget().getId())
                    .append(" : ")
                    .append(transition.getEvent())
                    .append(LF);
        }
        return sb.toString();
    }

    @Override
    public String visitOnExit(State<?, ?, ?> state) {
        return "";
    }
}
java 复制代码
/**
 * SysOutVisitor
 *
 * @author Frank Zhang
 * @date 2020-02-08 8:48 PM
 */
public class SysOutVisitor implements Visitor {

    @Override
    public String visitOnEntry(StateMachine<?, ?, ?> stateMachine) {
        String entry = "-----StateMachine:"+stateMachine.getMachineId()+"-------";
        System.out.println(entry);
        return entry;
    }

    @Override
    public String visitOnExit(StateMachine<?, ?, ?> stateMachine) {
        String exit = "------------------------";
        System.out.println(exit);
        return exit;
    }

    @Override
    public String visitOnEntry(State<?, ?, ?> state) {
        StringBuilder sb = new StringBuilder();
        String stateStr = "State:"+state.getId();
        sb.append(stateStr).append(LF);
        System.out.println(stateStr);
        for(Transition transition: state.getAllTransitions()){
            String transitionStr = "    Transition:"+transition;
            sb.append(transitionStr).append(LF);
            System.out.println(transitionStr);
        }
        return sb.toString();
    }

    @Override
    public String visitOnExit(State<?, ?, ?> visitable) {
        return "";
    }
}

至此,应用访问者模式,实现了将被访问类和访问操作进行逻辑隔离、解耦。

相关推荐
追逐时光者7 分钟前
一个开源的 Blazor 跨平台入门级实战项目
后端·.net
绝无仅有1 小时前
使用 Docker 安装 Elastic Stack 并重置本地密码
后端·面试·github
老A技术联盟1 小时前
聊一聊消息中间件的后起之秀-pulsar及其实践
后端
隐-梵1 小时前
Android studio前沿开发--利用socket服务器连接AI实现前后端交互(全站首发思路)
android·服务器·人工智能·后端·websocket·android studio·交互
uhakadotcom1 小时前
Langflow:零基础快速上手AI流程可视化开发工具详解与实战案例
后端·面试·github
bobz9651 小时前
strongswan ipsec 端口使用
后端
陈哥聊测试2 小时前
这款自研底层框架,你说不定已经用上了
前端·后端·开源
Light602 小时前
Python依赖注入完全指南:高效解耦、技术深析与实践落地
python·设计模式·单元测试·fastapi·依赖注入·解耦
一只叫煤球的猫2 小时前
分布式-跨服务事务一致性的常见解决方案
java·分布式·后端
扣丁梦想家2 小时前
Spring Boot 实现 Excel 导出功能(支持前端下载 + 文件流)
spring boot·后端·excel