[设计模式学习笔记]访问者模式
访问者模式
-
定义:
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?