文章目录

  • 1. 引入
  • 2. 访问模式的特性
  • 3. UML
  • 4. demo


1. 引入

我们都知道 计算机程序 = 算法 + 数据结构

再举一个例子,面向对象编程时,一个类定义通常也是由属性方法组成的。也就是说,一个类的行为在定义时就完全确定了

而访问者模式(Visitor),就是一种用来将数据结构和算法进行解耦的设计模式。符合开放关闭原则

访问者模式是Gof 23种设计模式之一,维基百科的介绍如下
wiki简介

2. 访问模式的特性

  • 设计目的:将固定的数据结构与灵活的算法解耦
  • 优势:可以不改动类结构为对象添加虚拟的方法
  • 劣势:扩展原始的类时,要考虑修改所有的visitor,不利于扩展
  • 适用场景:数据结构相对稳定的场景,如ASM框架中

网上很多教程会强调很多不同类可以实现不同的方法,个人认为这只是访问模式的扩展特性,其核心还是为固定的结构扩展虚拟的方法

3. UML


«interface» IVisitor visit(IElement element) Visitor void visit Element String name String version void accept «interface» IElement accept(Ivisitor visitor) client 调用


4. demo

场景:手机都是相对固定的组成,现在要添加5G功能,代码如下

  1. 入口
/**
 * 程序 = 数据结构 + 算法
 * visitor模式
 * 目的:让 数据结构 与 算法 解耦,符合开放关闭原则
 * 优势:可以不改动类结构为对象添加虚拟的方法 (wiki https://en.wikipedia.org/wiki/Visitor_pattern#Overview)
 * 劣势:扩展原始的类时,要考虑修改所有的visitor,不利于扩展
 * 适用场景:数据结构非常稳定
 */
public class Client {

    public static void main(String[] args) {
        HwPhone phone = new HwPhone("p40", "华为");
        IPhone iPhone = new IPhone("iphone11", "apple");

        // 扩展一个执行5G的方法
        IVisitor fifthVisitor= new FifthVisitor();
        phone.accept(fifthVisitor);
        iPhone.accept(fifthVisitor);

    }
}
  1. Visitor
/**
 * 访问者接口
 * @Author 
 * @Date 7:15 下午 2020/9/24
 */
public interface IVisitor {

    // 访问华为phone
    void visit(HwPhone phone);

    // 访问IPhone
    void visit(IPhone phone);

}
/**
 * 5G扩展
 * @Author 
 * @Date 3:29 下午 2020/9/27
 */
public class FifthVisitor implements IVisitor{
    @Override
    public void visit(HwPhone phone) {
        String msg = "【" + phone.getName() + phone.getVersion() + "】5G通信中...";
        System.out.println(msg);
    }

    @Override
    public void visit(IPhone phone) {
        String msg = "【" + phone.getName() + phone.getVersion() + "】暂不支持5G";
        System.out.println(msg);
    }
}
  1. Phone
    需要扩展虚拟方法的类
/**
 * 手机接口
 * @Author 
 * @Date 7:09 下午 2020/9/24
 */
public interface CellPhone {

    // 接受visitor的访问和操作(对自己进行操作)
    void accept(IVisitor visitor);
}
public class HwPhone implements CellPhone{

    private String version;
    private String name;

    public HwPhone(String version, String name) {
        this.version = version;
        this.name = name;
    }

    @Override
    public void accept(IVisitor visitor) {
        // 调用visitor的增强方法
        visitor.visit(this);

        // 此处甚至可以调用visitor中的其他方法
        // 例如,只visit name
    }

    public String getVersion() {
        return version;
    }
    public String getName() {
        return name;
    }
}
/**
 * 苹果手机
 * @Author 
 * @Date 7:39 下午 2020/9/24
 */
public class IPhone implements CellPhone {
    private String version;
    private String name;

    public IPhone(String version, String name) {
        this.version = version;
        this.name = name;
    }

    @Override
    public void accept(IVisitor visitor) {
        visitor.visit(this);
    }

    public String getVersion() {
        return version;
    }

    public String getName() {
        return name;
    }
}
  1. 运行结果

    可以看到,在没有修改phone类的情况下,通过accept方法可以为其灵活扩展类中不存在的虚拟方法