• Java设计模式之访问者模式


    1. 访问者模式

    1.1 定义、优缺点、适用场景

    定义:访问者模式(Visitor Pattern),封装一些作用于某种数据结构的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。基本工作原理是:在被访问的类里面加一个对外提供接待访问者的接口

    优点

    • 可以很方便的添加新的访问者,保证了开闭原则,利于维护
    • 将数据结构与数据操作分离,解决数据结构和操作耦合性问题
    • 符合单一职责原则、让程序具有优秀的扩展性、灵活性非常高
    • 可以对功能进行统一,可以做报表、UI、拦截器与过滤器,适用于数据结构相对稳定的系统

    缺点

    • 不能方便的添加新的元素者
    • 具体元素对访问者公布细节,也就是说访问者关注了其他类的内部细节,这是迪米特法则所不建议的, 这样造成了具体元素变更比较困难
    • 违背了依赖倒转原则。访问者依赖的是具体元素,而不是抽象元素

    适用场景

    • 需要对一个对象结构中的对象进行很多不同操作(这些操作彼此没有关联),同时需要避免让这些操作"污染"这些对象的类,可以用访问者模式解决
    • 不同的访问者对被访问者的关注点不一样。且想很方便的添加访问者,不添加新的被访问者
    • 一个系统有比较稳定的数据结构,又有经常变化的功能需求,那么访问者模式就比较合适

    1.2 模式的结构与实现

    结构

    • 抽象元素类(Element):定义一个accept 方法,接收一个访问者对象
    • 具体元素类(ConcreteElement):实现了accept方法
    • 抽象访问类(Visitor):为该对象结构中的ConcreteElement的每一个类声明一个visit操作
    • 具体访问类(ConcreteVisitor):实现Visitor声明的操作,是每个操作实现的部分
    • 对象结构(ObjectStructure):对象结构是一个抽象表述,它内部管理了元素集合,并且可以迭代这些元素提供访问者访问

    实现
    公司年终考核项目:CEO和CTO对工程师和销售员考核时,CEO关注的重点和CTO关注的重点是不一样的。而且可以很方便的添加其它领导对员工进行考核

    import java.util.ArrayList;
    import java.util.List;
    
    public class VisitorTest {
    
        public static void main(String[] args) {
    
            ObjectStructure objectStructure = new ObjectStructure();
            // 添加员工,进行统一管理
            objectStructure.add(new Engineer());
            objectStructure.add(new Saler());
    
            // CEO对所有员工进行考核
            System.out.println("======CEO开始进行考核=======");
            Visitor ceoVisitor = new CeoVisitor();
            objectStructure.leaderCheckStaff(ceoVisitor);
    
            // CTO对所有员工进行考核
            System.out.println("======CTO开始进行考核=======");
            Visitor ctoVisitor = new CtoVisitor();
            objectStructure.leaderCheckStaff(ctoVisitor);
        }
    
    }
    
    // 抽象元素类-员工
    abstract class Staff {
    
        // 员工接受领导的考核
        public abstract void accept(Visitor visitor);
    }
    
    
    // 这里用到了双分派。不管类怎么变化,我们都能找到期望的方法运行。意味着得到执行的操作取决于请求的种类和接收者的类型
    // 第一次分派:VisitorTest客户端中,将visitor作为参数传递给engineer的accept方法
    // 第二次分派:engineer类对象将自身作为参数传递给visitor的checkEngineer方法
    
    // 具体元素类-工程师
    class Engineer extends Staff {
    
        @Override
        public void accept(Visitor visitor) {
            // 领导对工程师的考核,不同的领导考核点不一样
            visitor.checkEngineer(this);
        }
    
    }
    
    
    // 具体元素类-销售员
    class Saler extends Staff {
    
        @Override
        public void accept(Visitor visitor) {
            // 领导对销售员的考核,不同的领导考核点不一样
            visitor.checkSaler(this);
        }
    
    }
    
    
    // 抽象访问类
    abstract class Visitor {
    
        // 领导对工程师的考核
        public abstract void checkEngineer(Engineer engineer);
    
        // 领导对销售员的考核
        public abstract void checkSaler(Saler saler);
    }
    
    // 具体访问类-CEO
    class CeoVisitor extends Visitor {
    
        @Override
        public void checkEngineer(Engineer engineer) {
            System.out.println("CEO关注的是工程师给公司研发的新产品");
        }
    
        @Override
        public void checkSaler(Saler saler) {
            System.out.println("CEO关注的是销售员给公司带来的业绩");
        }
    
    }
    
    
    // 具体访问类-CTO
    class CtoVisitor extends Visitor {
    
        @Override
        public void checkEngineer(Engineer engineer) {
            System.out.println("CTO关注的是工程师的技术深度和广度");
        }
    
        @Override
        public void checkSaler(Saler saler) {
            System.out.println("CTO关注的是销售员的销售技巧");
        }
    
    
    }
    
    
    //数据结构:用集合对员工进行统一管理
    class ObjectStructure {
    
        private List staffs = new ArrayList();
    
        public void add(Staff staff) {
            this.staffs.add(staff);
        }
    
        public void remove(Staff staff) {
            this.staffs.remove(staff);
        }
    
        // 接收一个领导,对所有员工进行考核
        public void leaderCheckStaff(Visitor visitor) {
            for (Staff staff : this.staffs) {
                staff.accept(visitor);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124

    运行程序,结果如下:

    ======CEO开始进行考核=======
    CEO关注的是工程师给公司研发的新产品
    CEO关注的是销售员给公司带来的业绩
    ======CTO开始进行考核=======
    CTO关注的是工程师的技术深度和广度
    CTO关注的是销售员的销售技巧
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
  • 相关阅读:
    Python+Pytest+Allure+Yaml+Jenkins+GitLab接口自动化测试框架详解
    FFMpeg zoompan 镜头聚焦和移动走位
    Oracle函数之聚组函数
    <<Java>> 关于进程的那些事
    npm 包管理
    线上教育系统平台,企业如何才能运营呢?
    Python:for循环语句
    性能测试-性能工程落地的4个阶段(21)
    [思维]Ironforge 2022杭电多校第8场 1005
    umich cv-4-1 卷积网络基本组成部分介绍
  • 原文地址:https://blog.csdn.net/yy8623977/article/details/126718255