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


    目录

    1.访问者模式简介

    2.cola访问者模式应用

    2.1 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参数对象:

    1. public interface Visitable {
    2. String accept(final Visitor visitor);
    3. }

    StateImpl实现accept接口如下:

    1. public class StateImpl implements State {
    2. @Override
    3. public String accept(Visitor visitor) {
    4. String entry = visitor.visitOnEntry(this);
    5. String exit = visitor.visitOnExit(this);
    6. return entry + exit;
    7. }
    8. }

    StateMachineImpl实现accept接口如下:

    1. public class StateMachineImpl implements StateMachine {
    2. @Override
    3. public String accept(Visitor visitor) {
    4. StringBuilder sb = new StringBuilder();
    5. sb.append(visitor.visitOnEntry(this));
    6. for (State state : stateMap.values()) {
    7. sb.append(state.accept(visitor));
    8. }
    9. sb.append(visitor.visitOnExit(this));
    10. return sb.toString();
    11. }
    12. }

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

    2.2 cola访问者类图

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

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

    1. /**
    2. * Visitor
    3. *
    4. * @author Frank Zhang
    5. * @date 2020-02-08 8:41 PM
    6. */
    7. public interface Visitor {
    8. char LF = '\n';
    9. /**
    10. * @param visitable the element to be visited.
    11. * @return
    12. */
    13. String visitOnEntry(StateMachine visitable);
    14. /**
    15. * @param visitable the element to be visited.
    16. * @return
    17. */
    18. String visitOnExit(StateMachine visitable);
    19. /**
    20. * @param visitable the element to be visited.
    21. * @return
    22. */
    23. String visitOnEntry(State visitable);
    24. /**
    25. * @param visitable the element to be visited.
    26. * @return
    27. */
    28. String visitOnExit(State visitable);
    29. }
    • PlantUMLVisitor实现了针对State和StateMachine的plantuml方式的输出格式;
    • SysOutVisitor实现了对State和StateMachine简单日志输出;
    1. /**
    2. * PlantUMLVisitor
    3. *
    4. * @author Frank Zhang
    5. * @date 2020-02-09 7:47 PM
    6. */
    7. public class PlantUMLVisitor implements Visitor {
    8. /**
    9. * Since the state machine is stateless, there is no initial state.
    10. *
    11. * You have to add "[*] -> initialState" to mark it as a state machine diagram.
    12. * otherwise it will be recognized as a sequence diagram.
    13. *
    14. * @param visitable the element to be visited.
    15. * @return
    16. */
    17. @Override
    18. public String visitOnEntry(StateMachine visitable) {
    19. return "@startuml" + LF;
    20. }
    21. @Override
    22. public String visitOnExit(StateMachine visitable) {
    23. return "@enduml";
    24. }
    25. @Override
    26. public String visitOnEntry(State state) {
    27. StringBuilder sb = new StringBuilder();
    28. for(Transition transition: state.getAllTransitions()){
    29. sb.append(transition.getSource().getId())
    30. .append(" --> ")
    31. .append(transition.getTarget().getId())
    32. .append(" : ")
    33. .append(transition.getEvent())
    34. .append(LF);
    35. }
    36. return sb.toString();
    37. }
    38. @Override
    39. public String visitOnExit(State state) {
    40. return "";
    41. }
    42. }
    1. /**
    2. * SysOutVisitor
    3. *
    4. * @author Frank Zhang
    5. * @date 2020-02-08 8:48 PM
    6. */
    7. public class SysOutVisitor implements Visitor {
    8. @Override
    9. public String visitOnEntry(StateMachine stateMachine) {
    10. String entry = "-----StateMachine:"+stateMachine.getMachineId()+"-------";
    11. System.out.println(entry);
    12. return entry;
    13. }
    14. @Override
    15. public String visitOnExit(StateMachine stateMachine) {
    16. String exit = "------------------------";
    17. System.out.println(exit);
    18. return exit;
    19. }
    20. @Override
    21. public String visitOnEntry(State state) {
    22. StringBuilder sb = new StringBuilder();
    23. String stateStr = "State:"+state.getId();
    24. sb.append(stateStr).append(LF);
    25. System.out.println(stateStr);
    26. for(Transition transition: state.getAllTransitions()){
    27. String transitionStr = " Transition:"+transition;
    28. sb.append(transitionStr).append(LF);
    29. System.out.println(transitionStr);
    30. }
    31. return sb.toString();
    32. }
    33. @Override
    34. public String visitOnExit(State visitable) {
    35. return "";
    36. }
    37. }

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

  • 相关阅读:
    『德不孤』Pytest框架 — 11、Pytest中Fixture装饰器(一)
    技术分享 | 云原生多模型 NoSQL 概述
    java上传文件到指定服务器
    众筹DAO“枯萎”的缩影:曾拍下《沙丘》未出版手稿的Spice DAO解散
    [MySQL]DQL,Data Query Language(数据查询语言)
    Mall脚手架总结(三) —— MongoDB存储浏览数据
    Qt TCP 分包粘包的解决方法
    总结一些 spark 处理小trick
    暑假卷的最厉害的居然人工智能,人工智能该如何学习?详细的AI【学习路线】与【资料推荐】
    【Redis】渐进式遍历
  • 原文地址:https://blog.csdn.net/supzhili/article/details/134033868