为什么支持双分派的语言不需要访问者模式?

Double Dispatch, 指的是执行哪个对象的方法,根据对象的运行时类型来决定;执行对象的哪个方法,根据方法参数的运行时类型来决定。

Single Dispatch,指的是执行哪个对象的方法,根据对象的运行时类型来决定

如何理解“Dispatch”这个单词呢? 在面向对象编程语言中,我们可以把方法调用理解为一种消息传递,也就是“Dispatch”。一个对象调用另一个对象的方法,就相当于给它发送一条消息。这条消息起码要包含对象名、方法名、方法参数。

如何理解“Single”“Double”这两个单词呢?“Single”“Double”指的是执行哪个对象的哪个方法,跟几个因素的运行时类型有关。我们进一步解释一下。Single Dispatch 之所以称为“Single”,是因为执行哪个对象的哪个方法,只跟“对象”的运行时类型有关。Double Dispatch 之所以称为“Double”,是因为执行哪个对象的哪个方法,跟“对象”和“方法参数”两者的运行时类型有关。

  1. public class ParentClass {
  2. public void f() {
  3. System.out.println("I am ParentClass's f().");
  4. }
  5. }
  6. public class ChildClass extends ParentClass {
  7. public void f() {
  8. System.out.println("I am ChildClass's f().");
  9. }
  10. }
  11. public class SingleDispatchClass {
  12. public void polymorphismFunction(ParentClass p) {
  13. p.f();
  14. }
  15. public void overloadFunction(ParentClass p) {
  16. System.out.println("I am overloadFunction(ParentClass p).");
  17. }
  18. public void overloadFunction(ChildClass c) {
  19. System.out.println("I am overloadFunction(ChildClass c).");
  20. }
  21. }
  22. public class DemoMain {
  23. public static void main(String[] args) {
  24. SingleDispatchClass demo = new SingleDispatchClass();
  25. ParentClass p = new ChildClass();
  26. demo.polymorphismFunction(p);//执行哪个对象的方法,由对象的实际类型决定
  27. demo.overloadFunction(p);//执行对象的哪个方法,由参数对象的声明类型决定
  28. }
  29. }
  30. //代码执行结果:
  31. I am ChildClass's f().
  32. I am overloadFunction(ParentClass p).

demo.overloadFunction(p); 中, 函数参数也参与决定

  • 多态 - 调用实际类型
  • 重载 - 调用声明类型

除了访问者模式,上一节的例子还有其他实现方案吗?

  • 工厂模式
  1. public abstract class ResourceFile {
  2. protected String filePath;
  3. public ResourceFile(String filePath) {
  4. this.filePath = filePath;
  5. }
  6. public abstract ResourceFileType getType();
  7. }
  8. public class PdfFile extends ResourceFile {
  9. public PdfFile(String filePath) {
  10. super(filePath);
  11. }
  12. @Override
  13. public ResourceFileType getType() {
  14. return ResourceFileType.PDF;
  15. }
  16. //...
  17. }
  18. //...PPTFile/WordFile跟PdfFile代码结构类似,此处省略...
  19. public interface Extractor {
  20. void extract2txt(ResourceFile resourceFile);
  21. }
  22. public class PdfExtractor implements Extractor {
  23. @Override
  24. public void extract2txt(ResourceFile resourceFile) {
  25. //...
  26. }
  27. }
  28. //...PPTExtractor/WordExtractor跟PdfExtractor代码结构类似,此处省略...
  29. public class ExtractorFactory {
  30. private static final Map<ResourceFileType, Extractor> extractors = new HashMap<>();
  31. static {
  32. extractors.put(ResourceFileType.PDF, new PdfExtractor());
  33. extractors.put(ResourceFileType.PPT, new PPTExtractor());
  34. extractors.put(ResourceFileType.WORD, new WordExtractor());
  35. }
  36. public static Extractor getExtractor(ResourceFileType type) {
  37. return extractors.get(type);
  38. }
  39. }
  40. public class ToolApplication {
  41. public static void main(String[] args) {
  42. List<ResourceFile> resourceFiles = listAllResourceFiles(args[0]);
  43. for (ResourceFile resourceFile : resourceFiles) {
  44. Extractor extractor = ExtractorFactory.getExtractor(resourceFile.getType());
  45. extractor.extract2txt(resourceFile);
  46. }
  47. }
  48. private static List<ResourceFile> listAllResourceFiles(String resourceDirectory) {
  49. List<ResourceFile> resourceFiles = new ArrayList<>();
  50. //...根据后缀(pdf/ppt/word)由工厂方法创建不同的类对象(PdfFile/PPTFile/WordFile)
  51. resourceFiles.add(new PdfFile("a.pdf"));
  52. resourceFiles.add(new WordFile("b.word"));
  53. resourceFiles.add(new PPTFile("c.ppt"));
  54. return resourceFiles;
  55. }
  56. }