博客
关于我
大白话聊访问者模式:从入门到实践
阅读量:416 次
发布时间:2019-03-06

本文共 2727 字,大约阅读时间需要 9 分钟。

访问者模式:从理论到实践

访问者模式是一种软件设计模式,其核心思想是通过封装操作,实现对数据结构的灵活扩展。这种模式在软件开发中广泛应用,尤其是在需要对已有代码库进行扩展时,能够有效避免对原有代码的修改。

访问者模式的定义

访问者模式的核心思想是:在不改变数据结构的前提下,定义新的操作。具体而言,访问者模式通过定义一个接口(Visitor),将对数据结构中各元素的操作封装进去。这样,系统的核心逻辑可以保持不变,而新增的功能可以通过实现不同的访问者类来实现。

以科学家接受采访的情景为例:访谈流程是固定的,包括三个部分:学校经历、工作经历和科研成果。但不同记者的采访内容会有所不同。这种变化可以通过访问者模式实现:定义一个Visitor接口,分别在每个访问者类中实现对应的采访方法。

访问者模式的实现

###Visitor接口Visitor接口定义了所有可能的访问操作。例如:

public interface Visitor {    void askSchoolExperience(String name);    void askWorkExperience(String name);    void askScienceAchievement(String name);}

###具体访问者类每个具体的访问者类实现Visitor接口,定义自己的访问逻辑。例如,新华社的记者可能更关心科研成果,而青年报的记者可能更关注精神层面的东西。

public class XinhuaVisitor implements Visitor {    @Override    public void askSchoolExperience(String name) {        System.out.println("请问" + name + ":在学校取得的最大成就是什么?");    }    //其他方法类似...}

###被访问者类被访问者类(Element)通过一个accept方法接收访问者对象。例如,科学家的类可以有一个accept方法,将访问者传递给内部逻辑。

public class Scientist {    private Visitor visitor;    private String name;        public Scientist(String name) {        this.name = name;    }        public void accept(Visitor visitor) {        this.visitor = visitor;    }        public void interview() {        visitor.askSchoolExperience(name);        visitor.askWorkExperience(name);        visitor.askScienceAchievement(name);    }}

###访问过程通过上述实现,可以看到访问者模式的核心逻辑:访问者通过interface定义了操作,具体访问者实现这些操作,被访问者通过accept方法将访问者接收进来,最后在interview方法中调用访问者的操作。

这种设计使得访谈流程固定不变,而采访内容的变化可以通过不同的访问者实现。

访问者模式的实际应用

###文件树遍历在JDK中,FileVisitor接口定义了文件遍历的操作。不同的遍历器可以实现不同的操作,比如统计文件数或打印文件名。

public interface FileVisitor {    FileVisitResult preVisitDirectory(T dir, BasicFileAttributes attrs);    FileVisitResult visitFile(T file, BasicFileAttributes attrs);    FileVisitResult postVisitDirectory(T dir, IOException exc);}

###字节码修改(ASM)ASM框架中的ClassVisitor类通过继承FileVisitor接口,实现了对字节码的修改。ClassReader类作为被访问者,负责读取和解析字节码。

public class ClassReader {    public ClassReader(byte[] classfile) {        //解析字节码并存储为Class对象    }        public ClassVisitor accept(ClassVisitor visitor) {        //调用visitor的各个方法        visitor.visitClass(...);        return visitor;    }}

ClassWriter类则是ClassVisitor的实现类,负责输出修改后的字节码。

public class ClassWriter implements ClassVisitor {    public ClassWriter(ClassVisitor visitor) {        //初始化    }        @Override    public ClassVisitor visitClass(...) {        //修改字节码        return this;    }        //其他方法类似...}

这种设计使得字节码的修改与原有框架无关,提高了扩展性。

当然使用访问者模式

访问者模式在以下场景下表现出色:

  • 需要对已有代码库进行扩展,而无需修改原有代码。
  • 需要支持多种操作,但核心逻辑保持不变。
  • 需要通过参数传递状态或行为,但不想改变已有结构。
  • ###优点

  • 高可维护性:固定不变的逻辑只需修改访问者类。
  • 灵活扩展性:新增功能只需添加新的访问者类。
  • 减少耦合度:减少被访问者与访问者之间的依赖。
  • ###缺点

  • 增加了复杂性:引入多个类需要更多的管理。
  • 被访问者难以扩展:一旦被访问者结构固定,修改难度大。
  • 参考资料

  • 《设计模式》
  • JDK的FileVisitor接口
  • ASM框架文档
  • 访问者模式是一种强大的设计模式,其核心在于通过抽象化的接口实现灵活的扩展。如果你的项目需要对已有代码进行扩展,而无需频繁修改核心逻辑,那么访问者模式绝对值得考虑。

    转载地址:http://riakz.baihongyu.com/

    你可能感兴趣的文章
    NPM 2FA双重认证的设置方法
    查看>>
    npm build报错Cannot find module ‘webpack/lib/rules/BasicEffectRulePlugin‘解决方法
    查看>>
    npm build报错Cannot find module ‘webpack‘解决方法
    查看>>
    npm ERR! ERESOLVE could not resolve报错
    查看>>
    npm ERR! Unexpected end of JSON input while parsing near ‘...“:“^1.2.0“,“vue-html-‘ npm ERR! A comp
    查看>>
    npm error Missing script: “server“npm errornpm error Did you mean this?npm error npm run serve
    查看>>
    npm error MSB3428: 未能加载 Visual C++ 组件“VCBuild.exe”。要解决此问题,1) 安装
    查看>>
    npm install CERT_HAS_EXPIRED解决方法
    查看>>
    npm install digital envelope routines::unsupported解决方法
    查看>>
    npm install 卡着不动的解决方法
    查看>>
    npm install 报错 EEXIST File exists 的解决方法
    查看>>
    npm install 报错 ERR_SOCKET_TIMEOUT 的解决方法
    查看>>
    npm install 报错 Failed to connect to github.com port 443 的解决方法
    查看>>
    npm install 报错 fatal: unable to connect to github.com 的解决方法
    查看>>
    npm install 报错 no such file or directory 的解决方法
    查看>>
    npm install 权限问题
    查看>>
    npm install报错,证书验证失败unable to get local issuer certificate
    查看>>
    npm install无法生成node_modules的解决方法
    查看>>
    npm install的--save和--save-dev使用说明
    查看>>
    npm node pm2相关问题
    查看>>