• 每天一个设计模式之访问者模式(Visitor Pattern)


    设计模式有23种之多,要想记住这二十多种模式的确不太容易,但是如果将模式的名字与典型的场景结合起来可能会更容易记忆。对于访问者模式,一个典型的例子就是不同的游客(visitor)游览一个地方不同的景区

    访问者模式的意图是将易变的操作和稳定的数据结构分离开。文本典型的例子中,一个地方的景区基本上是稳定不变的,而对不同游客所做的优惠活动则会有很多不同的类型,比如学生游客,教师游客,老年游客,外国游客,抗疫志愿者游客等等。

    一、UML类图

    在这里插入图片描述

    二、代码示例

    Visitor接口

    public interface Visitor {
        void visitSummerPalace(SummerPalace summerPalace);
        void visitTheGreatWall(TheGreatWall theGreatWall);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    Visitor具体类 - 学生visitor

    public class StudentVisitor implements Visitor {
        @Override
        public void visitSummerPalace(SummerPalace summerPalace) {
            double v = summerPalace.ticketRate() * 0.5;
            System.out.println("half price to visit SummerPalace for students. # The price is $" + v);
        }
    
        @Override
        public void visitTheGreatWall(TheGreatWall theGreatWall) {
            double v = theGreatWall.ticketRate() * 0.5;
            System.out.println("half price to visit The Great Wall for students. # The price is $" + v);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    Visitor具体类 - 抗疫英雄visitor

    public class FightCovidHeroVisitor implements Visitor {
        @Override
        public void visitSummerPalace(SummerPalace summerPalace) {
            double v = summerPalace.ticketRate() * 0.0;
            System.out.println("free to visit SummerPalace for fighting Convid-19 heroes. # The price is $" + v);
        }
    
        @Override
        public void visitTheGreatWall(TheGreatWall theGreatWall) {
            double v = theGreatWall.ticketRate() * 0.0;
            System.out.println("free to visit The Great Wall for fighting Convid-19 heroes. The price is $" + v);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    Element接口

    public interface ScenerySpot {
        void accept(Visitor visitor);
        int ticketRate();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    Element具体类 - 颐和园

    public class SummerPalace implements ScenerySpot {
    
        @Override
        public void accept(Visitor visitor) {
            visitor.visitSummerPalace(this);
        }
    
        @Override
        public int ticketRate() {
            return 120;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    Element具体类 - 长城

    public class TheGreatWall implements ScenerySpot {
    
        @Override
        public void accept(Visitor visitor) {
            visitor.visitTheGreatWall(this);
        }
    
        @Override
        public int ticketRate() {
            return 100;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    Object Structure - 旅游管理中心

    public class BeijingTourismCenter {
        private Set<ScenerySpot> scenerySpotSet = new HashSet<>();
    
        public void accept(Visitor visitor) {
            for (ScenerySpot spot : scenerySpotSet)
                spot.accept(visitor);
        }
    
        public void add(ScenerySpot spot) {
            scenerySpotSet.add(spot);
        }
    
        public void remove(ScenerySpot spot) {
            scenerySpotSet.remove(spot);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    客户类

    public class Client {
        public static void main(String[] args) {
            BeijingTourismCenter tourismCenter = new BeijingTourismCenter();
            tourismCenter.add(new SummerPalace());
            tourismCenter.add(new TheGreatWall());
            // add more...
    
            tourismCenter.accept(new FightCovidHeroVisitor());
            System.out.println("----------------------------");
            tourismCenter.accept(new StudentVisitor());
            // accept more...
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    运行结果

    free to visit SummerPalace for fighting Convid-19 heroes. # The price is $0.0
    free to visit The Great Wall for fighting Convid-19 heroes. The price is $0.0
    ----------------------------
    half price to visit SummerPalace for students. # The price is $60.0
    half price to visit The Great Wall for students. # The price is $50.0
    
    Process finished with exit code 0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    三、补充说明

    访问者模式包含一个 Double dispatch (双分派)的概念。

    spot.accept(visitor);
    
    • 1

    spot 是动态绑定的,visitor 也是动态绑定的。

    四、参考

    1. https://www.runoob.com/design-pattern/visitor-pattern.html
    2. https://www.baeldung.com/java-visitor-pattern
    3. https://cloud.tencent.com/developer/article/1755832
  • 相关阅读:
    yolov7基础知识先导篇
    C++之多态
    链接到语音识别控制面板时发生错误(0x80004005L)
    Java解析Json格式数据
    leetcode522. 最长特殊序列 II(java)
    Enhancing Self-Consistency and Performance of Pre-Trained Language Model
    SpringBoot+Vue项目自习室座位预约系统
    软件测试行业5年经验,薪资不如刚入行的应届生,真是日了狗了,问题究竟出在哪里?
    在浏览器中运行 TensorFlow.js 来训练模型并给出预测结果(Iris 数据集)
    XML基础知识汇总
  • 原文地址:https://blog.csdn.net/M_sdn/article/details/126359091