[设计模式学习笔记]访问者模式

访问者模式

  • 定义:
    Allows for one or more operation to be applied to a set of objects at runtime, decoupling the operations from the object structure.
    允许一个或者多个操作应用到一组对象上,解耦操作和对象本身.

  • 问题和背景:
    读取不同文件类型的内容并写入到txt.
    PDF,PPT,WORD -> txt

  • 第一个版本:
    创建一个资源文件类(抽象类),定义文件的解析方法
    基于资源文件类,分别创建pdf,ppt,word的文件类,重写解析方法

  • 第二个版本:
    将解析方法抽出来放到一个解析类里面,和文件类解耦.将解析方法写成重载函数(同一个类中函数名相同,参数不同).
    重载函数的参数是文件类的对象,比如PPTFile, PdfFile, WordFile.
    但是仅仅写了几个重载函数,在编译时会报错,这些函数无法对应正确的文件对象.
    为了解决这个问题:
    在资源文件类里添加一个方法accept(),参数是解析类的对象.然后不同文件类在基于资源文件类创建的时候,重写accept(),在方法里调用解析器类的解析方法,传入当前类的对象.这样,解析类在编译的时候就会根据该文件类去选择对应的解析方法.

  • 第三个版本:
    如果添加新的文件处理方法,比如压缩.则在资源文件类里添加一个accept()方法.然后文件类重写accept(),在方法里调用压缩类的压缩方法.
    但是这样违反了开闭原则,每次添加新的文件处理功能都需要修改文件类的代码.

  • 第四个版本:
    为了解决第三个版本里的问题,创建一个Visitor接口.将Visitor接口设为资源文件类里的accept()方法的形参.并且,资源文件类里只需要一个accept()方法即可.在创建文件类的时候,也只需要重写一个accept()方法,在方法里调用一次Visitor.visit().
    所有的文件处理类(如解析类和压缩类)都实现Visitor()接口,重写visit()的重载函数,也就是说写多个visit()函数,每个函数处理不同类型的文件.
    这样子的话,当需要添加新的文件处理类,只要创建一个新的处理类并实现Visitor接口,然后主函数里添加调用逻辑即可.无需改动文件类的代码.

  • 类图:

  • 另外一种实现
    上述功能,还可以通过工厂模式实现。针对这个场景,实现起来比访问者模式更加简单。(如果扩展的功能不多的话,可以使用工厂模式。如果扩展的功能很多,则使用访问者模式,因为可以减少很多代码。)
    首先,定义一个包含解析方法的解析接口,多个解析器都实现这个接口,并重写方法。
    然后,写一个工厂类,在类里面通过hashmap存储解析类和文件类型的对应关系。
    最后,调用的时候,通过传入文件类型到工厂类获取对应的解析类。
    如果有新增功能,比如添加一个压缩功能。则增加一个压缩接口,多个压缩类实现压缩接口。再写一个压缩的工厂类,将不同文件类型和压缩类一一对应。


  • single dispatch
    执行哪个对象的方法,根据对象的运行时类型来决定;
    执行对象的哪个方法,根据方法参数的编译时类型来决定。

  • double dispatch
    执行哪个对象的方法,根据对象的运行时类型来决定;
    执行对象的哪个方法,根据方法参数的运行时类型来决定。

  • 问题:
    有哪些编程语言支持single dispatch?
    Java、C++、C#
    有哪些编程语言支持double dispatch?

posted @ 2022-06-11 18:03  Shengjie  阅读(19)  评论(0编辑  收藏  举报