为什么支持双分派的语言不需要访问者模式?
Double Dispatch, 指的是执行哪个对象的方法,根据对象的运行时类型来决定;执行对象的哪个方法,根据方法参数的运行时类型来决定。
Single Dispatch,指的是执行哪个对象的方法,根据对象的运行时类型来决定
如何理解“Dispatch”这个单词呢? 在面向对象编程语言中,我们可以把方法调用理解为一种消息传递,也就是“Dispatch”。一个对象调用另一个对象的方法,就相当于给它发送一条消息。这条消息起码要包含对象名、方法名、方法参数。
如何理解“Single”“Double”这两个单词呢?“Single”“Double”指的是执行哪个对象的哪个方法,跟几个因素的运行时类型有关。我们进一步解释一下。Single Dispatch 之所以称为“Single”,是因为执行哪个对象的哪个方法,只跟“对象”的运行时类型有关。Double Dispatch 之所以称为“Double”,是因为执行哪个对象的哪个方法,跟“对象”和“方法参数”两者的运行时类型有关。
public class ParentClass {public void f() {System.out.println("I am ParentClass's f().");}}public class ChildClass extends ParentClass {public void f() {System.out.println("I am ChildClass's f().");}}public class SingleDispatchClass {public void polymorphismFunction(ParentClass p) {p.f();}public void overloadFunction(ParentClass p) {System.out.println("I am overloadFunction(ParentClass p).");}public void overloadFunction(ChildClass c) {System.out.println("I am overloadFunction(ChildClass c).");}}public class DemoMain {public static void main(String[] args) {SingleDispatchClass demo = new SingleDispatchClass();ParentClass p = new ChildClass();demo.polymorphismFunction(p);//执行哪个对象的方法,由对象的实际类型决定demo.overloadFunction(p);//执行对象的哪个方法,由参数对象的声明类型决定}}//代码执行结果:I am ChildClass's f().I am overloadFunction(ParentClass p).
demo.overloadFunction(p); 中, 函数参数也参与决定
- 多态 - 调用实际类型
- 重载 - 调用声明类型
除了访问者模式,上一节的例子还有其他实现方案吗?
- 工厂模式
public abstract class ResourceFile {protected String filePath;public ResourceFile(String filePath) {this.filePath = filePath;}public abstract ResourceFileType getType();}public class PdfFile extends ResourceFile {public PdfFile(String filePath) {super(filePath);}@Overridepublic ResourceFileType getType() {return ResourceFileType.PDF;}//...}//...PPTFile/WordFile跟PdfFile代码结构类似,此处省略...public interface Extractor {void extract2txt(ResourceFile resourceFile);}public class PdfExtractor implements Extractor {@Overridepublic void extract2txt(ResourceFile resourceFile) {//...}}//...PPTExtractor/WordExtractor跟PdfExtractor代码结构类似,此处省略...public class ExtractorFactory {private static final Map<ResourceFileType, Extractor> extractors = new HashMap<>();static {extractors.put(ResourceFileType.PDF, new PdfExtractor());extractors.put(ResourceFileType.PPT, new PPTExtractor());extractors.put(ResourceFileType.WORD, new WordExtractor());}public static Extractor getExtractor(ResourceFileType type) {return extractors.get(type);}}public class ToolApplication {public static void main(String[] args) {List<ResourceFile> resourceFiles = listAllResourceFiles(args[0]);for (ResourceFile resourceFile : resourceFiles) {Extractor extractor = ExtractorFactory.getExtractor(resourceFile.getType());extractor.extract2txt(resourceFile);}}private static List<ResourceFile> listAllResourceFiles(String resourceDirectory) {List<ResourceFile> resourceFiles = new ArrayList<>();//...根据后缀(pdf/ppt/word)由工厂方法创建不同的类对象(PdfFile/PPTFile/WordFile)resourceFiles.add(new PdfFile("a.pdf"));resourceFiles.add(new WordFile("b.word"));resourceFiles.add(new PPTFile("c.ppt"));return resourceFiles;}}
