Design Pattern 笔记

Visitor and Acyclic Visitor 小记

extensibility, behavioral

前言

在Design Pattern上面学习设计模式, 正遇到 Visitor 和 Acyclic Visitor模式, 都是访问者模式, 简言之, 将对象的功能放到外部类中实现, 完成功能和主要类结构的解耦, 通过double dispatch便可以获得准确的接口实现类从而执行对应方法, 下面代码说明;

Visitor & Acyclic Visitor

在Design Pattern: Visitor的文章或是Design Pattern: Acyclic Visitor文章了解到

其中对于访问者模式的应用主要解释为

  1. 在不改变或影响继承关系情况下, 增加新函数
  2. 新方法是属于这个主要功能体的继承关系中, 但是需要使用到新方法的情况
  3. 主要类的扩展较频繁的情况
  4. 编译blahblahblah

上述网站及很多的人对于该模式的解释都是用 Modem 这个概念来说明, 很多都直接照抄, 一开始看的有点模糊, 于是在这片博客visitor模式中看到了一个比较容易理解的实例: 基于各个geo模型导出xml的例子

上述实例中的地理对象存在多个实例 , 例如 city, industries, sightseeing areas, 如果需要对上述各个地理实例做导出xml数据的功能, 最直接的方法就是在各个实例中添加导出xml方法, 然后遍历所有实例并调用导出, 随之将带来一系列问题 : 文中提到, 系统架构不允许这么做,例如这个xml类是在引入的外部类库, 亦或者直接修改geo实例会影响生产环境的代码, 容易在添加导出方法时将不必要的潜在bug引入

其次是 导出XML方法 写在 geo实例中是否合理, 因为这些实例的主要作用就只是处理地理数据, 导出XML方法看起来不属于该对象本身应该有的能力, 直接添加到这个geo实例中看似很不合理, 最后是因为这种类似的功能需求很可能随时发生变化, 而且变化比较频繁, 下次导出个excel, 导出个其他格式? 每次都根据需求直接修改主要的这个geo对象也十分不合理.

所以在这里引入了Visitor模式, 也即将方法的实现提出来,放到外部接口中定义并实现, 通过double dispatch,确定了调用对应的实例对象,执行对应实例的方法, 主要是跟多态和面向接口有关

Visitor示例

传统访问者特点: Visitor实例ConcreteVisitors需要实现父接口(Visitor)中的所有方法

  • 扩展方法定义Visitor父类接口, 和实现
//最顶层的扩展功能接口 称之为Visitor
//可见对应方法中接收的是对应实例, 这样就可以在Geo对象accept时通过传入exportxxx()中的geo实例获取对应的数据
public interface Visitor{void exportCity(City c);void exportIndustry(Industry i);void exportSightSeeing(SightSeeing s);
}//这是一种写法
public class XmlExportVisitor implements Visitor {public void exportCity(City c){//导出city的xml}public void exportIndustry(Industry i){//导出industry的xml}public void exportSightSeeing(SightSeeing s){//导出SightSeeing的xml}
}//另一种写法是将方法当作对象使用 Visitor模式
//可见是只真实实现了对应的扩展功能,无关的功能都空实现
public class CityXmlExportVisitor implements Visitor {public void exportCity(City c){//导出city的xml}public void exportIndustry(Industry i){}public void exportSightSeeing(SightSeeing s){}
}public class IndustryXmlExportVisitor implements Visitor {public void exportCity(City c){}public void exportIndustry(Industry i){//导出industry的xml}public void exportSightSeeing(SightSeeing s){}
}public class SightSeeingXmlExportVisitor implements Visitor {public void exportCity(City c){}public void exportIndustry(Industry i){}public void exportSightSeeing(SightSeeing s){//导出SightSeeing的xml}
}
  • Geo类, 也即被扩展的类, 父类或父接口中定义accpte方法,接收一个Visitor对象
    这里也说明了,如果使用此模式去重构, 还是不可避免的需要修改到原代码业务实体的定义, 需要增加一个接受visitor的接口
//可见被扩展父类中定义的accept方法接收任意实现了Visitor接口的对象
public abstract class GeoObj {//....其他无关内容省略public abstract void accept(Visitor vistor);
}public class City extends GeoObj {public void accept(Visitor visitor){visitor.exportCity(this)}
}
//调用
City city = new City()
city.accept(new XmlExportVisitor());

但从上述代码也不难看出, 如果要增加一个新的导出方法, 那么之前所有实现该Visitor接口的子类都将要去实现这个方法, 这也是Visitor模式的一个弊端.

Acyclic Visitor示例

无环访问者特点: 将方法的定义推迟到子类接口中, 在被访问类中使用dynamic cast方式选择对应的访问者并调用方法

在Visitor的实现基础上, 对访问者抽象的进一步弱化, 不再将功能函数定义到访问者父类接口中, 也即Visitor接口中没有具体方法

  • 重新定义访问者接口
public interface Visitor{}public interface CityExportVisitor extends Visitor{void export(City c);
}//定义子类接口再继续实现
public interface CityXmlExportVisitor extends CityExportVisitor{void export(City c);
}
//实现一个导出
public class CityExcelExportVisitor implements CityExportVisitor {@Overridepublic void export(City c){//导出excel方法}
}
  • 被访问(被加强)的子类调整并调用导出功能
public class City extends GeoObj {public void accept(Visitor visitor){//判断后基于dynamic cast转型if(visitor instance of CityExportVisitor){((CityExportVisitor) visitor).export(this);} else {// log, error, do sth else or do nothing}}
}//调用
City c = new City();
c.accept(new CityExcelExportVisitor());

通过上述的代码就可以比较容易的理解acyclic visitor和visitor之间的区别了,acyclic visitor对访问者顶层接口抽象的退化, 将方法的定义推迟到对应具体实例的访问者子类接口中去定义和实现, 主要解决的就是传统visiot模式带来的循环问题, 由此可见对city类增加新导出方法时, 可以通过增加对应city的新访问者子类完成实现, 不会影响其他的类的visitor

但是使用到设计模式必然会带来一定的副作用, 例如Visitor模式中还是不可避免的需要调整被访问类的代码, 并增加接受访问者的接口等

Design Pattern: Visitor and Acyclic Visitor and their differences相关推荐

  1. 再议访问者模式 - Visitor vs Acyclic Visitor

    访问者模式的应用条件相对苛刻一些.通常它被使用在类似于这种场景:被访问类不太会增加新的子类,但是它的方法会经常变动. 先来简单回顾一些经典访问者. 传统Visitor模式 假设我们需要创建一个Encr ...

  2. Design Pattern - Visitor(C#)

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! Defi ...

  3. Visitor模式与Acyclic Visitor

    visitor模式最基本的是访问者和被访问者.它的优势是不用改变被访问类的任何结构就可以对被访问者施加新的操作,前提是增加一个访问者的子类.其实就是用增加访问者子类的方法替代被访问者方法的增加. 用你 ...

  4. 说说设计模式~大话目录(Design Pattern)

    回到占占推荐博客索引 设计模式(Design pattern)与其它知识不同,它没有华丽的外表,没有吸引人的工具去实现,它是一种心法,一种内功,如果你希望在软件开发领域有一种新的突破,一个质的飞越,那 ...

  5. Design Pattern Quick Overview

    Do we really need this design pattern? Just ignore, all the big guys requires it. For you, just unde ...

  6. 设计模式(Design Pattern)

    简介 设计模式(Design Pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用.设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案.这些解决方案是众多软件开发人 ...

  7. 设计模式(Design Pattern)详细整理(含思维导图)

    设计模式(Design Pattern) 设计模式(Design pattern)代表了最佳的实践,是软件开发人员在软件开发过程中面临的一般问题的解决方案.这些解决方案是众多软件开发人员经过相当长的一 ...

  8. 源于Design Pattern Explanation with C++ Implementation的 设计模式 C++

    1.创建型模式 (Creational Pattern) 1.1 工厂模式(Factory Pattern ) 1.2  抽象工厂模式(Abstract Factory Pattern ) 1.3   ...

  9. 几种常用的设计模式 (Design Pattern)

    文章目录 设计模式(Design Pattern) 一.设计模式的分类 1. 基础型模式 (Fundamental Pattern) 2. 创建型模式 (Creational Pattern) 3. ...

最新文章

  1. 容器 root权限运行_【漏洞通告】Containerd容器逃逸漏洞通告 (CVE202015257)
  2. ORA-4031错误深入解析
  3. 【译】 WebSocket 协议第十一章——IANA 注意事项(IANA Considerations)
  4. window for jdk install
  5. 查看数据库大小_查看Oracle 数据库的每天归档量及数据库大小
  6. CIO实施精细化管理的五个要点
  7. 蒙克:云计算安全问题被夸大
  8. LINQ是死是活?——很奇怪为什么会有这样的话题?
  9. 服务器红帽操作系统安装,pxe无人值守安装 红帽操作系统
  10. 实例分割——转置卷积的学习笔记
  11. 读书笔记--疯狂Android讲义 目录
  12. bzoj:2331: [SCOI2011]地板
  13. 输入输出知识点和问题超全总结(持续更新中)
  14. 【环球产品探寻 4】Wolftech News拥有一流用户体验的媒体工作流系统 - 挪威
  15. 【lzy学习笔记-dive into deep learning】数学预备 2.1-2.4
  16. 安卓设备TF卡概率性无法识别问题
  17. 10M/s,保姆级教程,制作自己的网盘不限速工具!
  18. python(2)兔子产子
  19. 大数据能让博彩公司破产
  20. 【手撕算法】FMM图像修复算法C++实现

热门文章

  1. 【Socket网络编程进阶与实战】------ Socket网络编程快速入门
  2. (翻译)Decision-Making in Driver-Automation Shared Control
  3. PTA-- 快速排序(25)
  4. 学习TypeScrip1(基础类型)
  5. 如何实现MYSQL高性能,高可用服务器架构
  6. 来说说datatype
  7. Flashback 技术
  8. 软件开发流程与初始软件测试
  9. 前端开发:JS中关于正则表达式的使用汇总
  10. stripped 和 not stripped