访问者模式

简介: 访问者模式

让自己的内心藏着一条巨龙,既是一种苦刑,也是一种乐趣——雨果

今天跟着一个网站学了学访问者模式

简单来说,如果我们要在不改动现有逻辑的情况下对类进行增强,则可以使用访问者模式

真实世界类比

image.png

优秀的保险代理人总能为不同类型的团体提供不同的保单。

假如有这样一位非常希望赢得新客户的资深保险代理人。 他可以拜访街区中的每栋楼, 尝试向每个路人推销保险。 所以, 根据大楼内组织类型的不同, 他可以提供专门的保单:

如果建筑是居民楼, 他会推销医疗保险。

如果建筑是银行, 他会推销失窃保险。

如果建筑是咖啡厅, 他会推销火灾和洪水保险。

我们这里有多栋建筑,但我们不能在建筑类中写推销保险的代码,并且尽可能考虑未来拓展性

当设计完成后,此时此刻突然来了是送外卖的,我们现在再改动原有每个建筑的代码了,工作量就会太多。。。

我们尝试用访问者模式去完成这样一个案例:

建筑接口

package com.ruben.vistor.example.Insurance;
/**
 * 建筑
 *
 * @author <achao1441470436@gmail.com>
 * @since 2021/7/18 15:11
 */
public interface Building {
    /**
     * 获取建筑名字
     *
     * @return java.lang.String
     * @author <achao1441470436@gmail.com>
     * @since 2021/7/18 15:48
     */
    String getName();
    /**
     * 到达建筑
     *
     * @author <achao1441470436@gmail.com>
     * @since 2021/7/18 15:58
     */
    void arrived();
    /**
     * 访问、拜访建筑
     *
     * @param person 访问者。人
     * @author <achao1441470436@gmail.com>
     * @since 2021/7/18 14:19
     */
    void beVisited(Person person);
}

这个建筑接口中有三个函数,前面两个函数是我们需要具体执行的函数,第三个函数则是提供一个入口,让建筑能够被人访问

它的参数里是一个Person类,对应人

我们现在先来实现这个Building接口,写出居民楼、银行、咖啡厅的代码

居民楼

package com.ruben.vistor.example.Insurance;
/**
 * 居民楼
 *
 * @author <achao1441470436@gmail.com>
 * @since 2021/7/18 15:11
 */
public class ResidentialBuilding implements Building {
    private String name;
    public ResidentialBuilding(String name) {
        this.name = name;
    }
    /**
     * 获取建筑名字
     *
     * @return java.lang.String
     * @author <achao1441470436@gmail.com>
     * @since 2021/7/18 15:48
     */
    @Override
    public String getName() {
        return name;
    }
    /**
     * 到达建筑
     *
     * @author <achao1441470436@gmail.com>
     * @since 2021/7/18 15:58
     */
    @Override
    public void arrived() {
        System.out.println("到达" + getName());
    }
    public void setName(String name) {
        this.name = name;
    }
    /**
     * 被访问、拜访建筑
     *
     * @param person 访问者。人
     * @author <achao1441470436@gmail.com>
     * @since 2021/7/18 14:19
     */
    @Override
    public void beVisited(Person person) {
        person.visit(this);
    }
}

银行

package com.ruben.vistor.example.Insurance;
/**
 * 银行
 *
 * @author <achao1441470436@gmail.com>
 * @since 2021/7/18 15:14
 */
public class Bank implements Building {
    private String name;
    public Bank(String name) {
        this.name = name;
    }
    /**
     * 获取建筑名字
     *
     * @return java.lang.String
     * @author <achao1441470436@gmail.com>
     * @since 2021/7/18 15:48
     */
    @Override
    public String getName() {
        return name;
    }
    /**
     * 到达建筑
     *
     * @author <achao1441470436@gmail.com>
     * @since 2021/7/18 15:58
     */
    @Override
    public void arrived() {
        System.out.println("到达" + getName());
    }
    public void setName(String name) {
        this.name = name;
    }
    /**
     * 访问、拜访建筑
     *
     * @param person 访问者。人
     * @author <achao1441470436@gmail.com>
     * @since 2021/7/18 14:19
     */
    @Override
    public void beVisited(Person person) {
        person.visit(this);
    }
}

咖啡厅

package com.ruben.vistor.example.Insurance;
/**
 * 咖啡厅
 *
 * @author <achao1441470436@gmail.com>
 * @since 2021/7/18 15:19
 */
public class CoffeeShop implements Building {
    private String name;
    public CoffeeShop(String name) {
        this.name = name;
    }
    /**
     * 获取建筑名字
     *
     * @return java.lang.String
     * @author <achao1441470436@gmail.com>
     * @since 2021/7/18 15:48
     */
    @Override
    public String getName() {
        return name;
    }
    /**
     * 到达建筑
     *
     * @author <achao1441470436@gmail.com>
     * @since 2021/7/18 15:58
     */
    @Override
    public void arrived() {
        System.out.println("到达" + getName());
    }
    public void setName(String name) {
        this.name = name;
    }
    /**
     * 访问、拜访建筑
     *
     * @param person 访问者。人
     * @author <achao1441470436@gmail.com>
     * @since 2021/7/18 14:19
     */
    @Override
    public void beVisited(Person person) {
        person.visit(this);
    }
}

然后是我们的Person接口,其中有对应访问三个建筑的方法

package com.ruben.vistor.example.Insurance;
/**
 * 人,访问者
 *
 * @author <achao1441470436@gmail.com>
 * @since 2021/7/18 15:17
 */
public interface Person {
    /**
     * 访问居民楼
     *
     * @param building 居民楼
     * @author <achao1441470436@gmail.com>
     * @since 2021/7/18 15:22
     */
    void visit(ResidentialBuilding building);
    /**
     * 访问银行
     *
     * @param building 银行
     * @author <achao1441470436@gmail.com>
     * @since 2021/7/18 15:22
     */
    void visit(Bank building);
    /**
     * 访问咖啡厅
     *
     * @param building 咖啡厅
     * @author <achao1441470436@gmail.com>
     * @since 2021/7/18 15:22
     */
    void visit(CoffeeShop building);
}

Person对应的实现类

接下来就是我们的保险推销员了,写上具体增强逻辑

我们建筑本身没有能够被保险人员上门推销保险这一个功能,它只能被人访问,因此我们写完增强逻辑,对齐进行赋能,这样我们的保险推销员能够针对不同的建筑推销对应的保险

package com.ruben.vistor.example.Insurance;
/**
 * 卖保险的
 *
 * @author <achao1441470436@gmail.com>
 * @since 2021/7/18 15:27
 */
public class InsuranceSeller implements Person {
    /**
     * 访问建筑
     *
     * @param building 建筑
     * @author <achao1441470436@gmail.com>
     * @since 2021/7/18 15:47
     */
    public void visit(Building building) {
        System.out.println("开始去" + building.getName() + "推销保险!");
        building.beVisited(this);
    }
    /**
     * 访问居民楼
     *
     * @param building 居民楼
     * @author <achao1441470436@gmail.com>
     * @since 2021/7/18 15:22
     */
    @Override
    public void visit(ResidentialBuilding building) {
        building.arrived();
        System.out.println("开始推销医疗保险");
    }
    /**
     * 访问银行
     *
     * @param building 银行
     * @author <achao1441470436@gmail.com>
     * @since 2021/7/18 15:22
     */
    @Override
    public void visit(Bank building) {
        building.arrived();
        System.out.println("开始推销失窃保险");
    }
    /**
     * 访问咖啡厅
     *
     * @param building 咖啡厅
     * @author <achao1441470436@gmail.com>
     * @since 2021/7/18 15:22
     */
    @Override
    public void visit(CoffeeShop building) {
        building.arrived();
        System.out.println("开始推销火灾、洪水保险");
    }
}

这里第一个函数通过上面对Building中第三个入口函数的调用,则调用到对应具体建筑的beVisited方法,其中又调用了Person中的visit方法,注意这里调用的就不是我们下面第一个函数了,而是对应具体实现类参数的那一个visit方法,如银行,则调用的是visit(Bank building)

最后则是调用

package com.ruben.vistor.example.Insurance;
/**
 * 卖保险
 *
 * @author <achao1441470436@gmail.com>
 * @since 2021/7/18 15:55
 */
public class SellInsurance {
    public static void main(String[] args) {
        InsuranceSeller insuranceSeller = new InsuranceSeller();
        Building residentialBuilding = new ResidentialBuilding("碧桂园");
        residentialBuilding.beVisited(insuranceSeller);
        Building bank = new Bank("农业银行");
        bank.beVisited(insuranceSeller);
        Building coffeeShop = new CoffeeShop("瑞幸咖啡");
        coffeeShop.beVisited(insuranceSeller);
    }
}

可以看到我这里成功让推销员对不同的建筑执行不同的逻辑,虽然是不同的子类,但我们传入的都是父类Building,但保险推销员能根据不同的子类执行不同的逻辑了

此时如果我们加一个送外卖的业务,则可以只加一个外卖员类

然后让外卖员类中实现对各个建筑的逻辑代码,即可让外卖员自己根据传入的建筑执行不同的逻辑

执行结果

访问者模式优缺点

优点:

1.开闭原则。 你可以引入在不同类对象上执行的新行为, 且无需对这些类做出修改。

2.单一职责原则。 可将同一行为的不同版本移到同一个类中。

3.访问者对象可以在与各种对象交互时收集一些有用的信息。 当你想要遍历一些复杂的对象结构 (例如对象树), 并在结构中的每个对象上应用访问者时, 这些信息可能会有所帮助。

缺点:

1.每次在元素层次结构中添加或移除一个类时, 你都要更新所有的访问者。(建了个奶茶店,你得在Person、保险推销员和外卖员中都新增这个建筑)

2.在访问者同某个元素进行交互时, 它们可能没有访问元素私有成员变量和方法的必要权限。

相关文章
|
4月前
|
设计模式 Java 容器
聊聊Java设计模式-访问者模式
访问者模式(Visitor Pattern)指将作用域某种数据结构中的各元素的操作分离出来封装成独立的类,使其在不改变数据结构的前提下可以添加作用于这些元素的新的操作。
28 3
|
5月前
|
算法
行为型 访问者模式
行为型 访问者模式
18 0
|
7月前
|
设计模式 算法 BI
设计模式~访问者模式(Visitor)-15
在访问者模式(Visitor Pattern)中,我们使用了一个访问者类,它改变了元素类的执行算法。通过这种方式,元素的执行算法可以随着访问者改变而改变。这种类型的设计模式属于行为型模式。根据模式,元素对象已接受访问者对象,这样访问者对
26 0
|
9月前
|
设计模式 Java uml
|
10月前
|
设计模式 Java uml
访问者模式
定义作用于对象元素的新操作。访问者模式将数据结构和对数据的操作分离开来,使得操作集合可以独立变化,同时也方便添加新的操作。
61 2
|
10月前
|
设计模式 Java 关系型数据库
访问者模式解读
访问者模式解读
|
11月前
今天说说你不知道的访问者模式
今天说说你不知道的访问者模式
54 0
|
设计模式 程序员
访问者模式是啥?咋实现呀?
访问者模式是啥?咋实现呀?
|
设计模式 Java Spring
Java设计模式 ->访问者模式
Java设计模式 ->访问者模式
76 0
|
设计模式
我学会了,访问者模式
访问者模式属于行为型模式,这个类型的设计模式总结出了 类、对象之间的经典交互方式,将类、对象的行为和使用解耦了,花式的去使用对象的行为来完成特定场景下的功能。
88 0
我学会了,访问者模式