极客时间之设计模式之美读后感

关于单分派和双分派

所谓 Single Dispatch,指的是执行哪个对象的方法,根据对象的运行时类型来决定;执行对象的哪个方法,根据方法参数的 编译时类型 来决定。所谓 Double Dispatch,指的是执行哪个对象的方法,根据对象的运行时类型来决定;执行对象的哪个方法,根据方法参数的 运行时类型 来决定。
如何理解“Dispatch”这个单词呢? 在面向对象编程语言中,我们可以把方法调用理解为一种消息传递,也就是“Dispatch”。一个对象调用另一个对象的方法,就相当于给它发送一条消息。这条消息起码要包含对象名、方法名、方法参数。
如何理解“Single”“Double”这两个单词呢?“Single”“Double”指的是执行哪个对象的哪个方法,跟几个因素的运行时类型有关。我们进一步解释一下。Single Dispatch之所以称为“Single”,是因为执行哪个对象的哪个方法,只跟“对象”的运行时类型有关。Double Dispatch 之所以称为“Double”,是因为执行哪个对象的哪个方法,跟“对象”和“方法参数”两者的运行时类型有关。
具体到编程语言的语法机制,Single Dispatch 和 Double Dispatch 跟多态和函数重载直接相关。当前主流的面向对象编程语言(比如,Java、C++、C#)都只支持 SingleDispatch,不支持 Double Dispatch。

Java 支持多态特性,代码可以在运行时获得对象的实际类型(运行时类型),然后根据实际类型决定调用哪个方法。尽管Java 支持函数重载,但 Java 设计的函数重载的语法规则是,并不是在运行时,根据传递进函数的参数的实际类型,来决定调用哪个重载函数,而是在编译时,根据传递进函数的参数的声明类型(也就是前面提到的编译时类型),来决定调用哪个重载函数。也就是说,具体执行哪个对象的哪个方法,只跟对象的运行时类型有关,跟参数的运行时类型无关。所以,Java 语言只支持 Single Dispatch。

  • 单分派:执行哪个对象的方法,只和对象的运行时类型有关,表现出来就是多态。
  • 双分派:执行哪个对象的方法,和对象及方法参数两者的运行时类型有关,java不支持。

代码示例:

public class TestDispatch {
    public static void main(String[] args) {
        SingleDispatchClass demo = new SingleDispatchClass();
        ParentClass p = new ChildClass();
        demo.polymorphismFunction(p); // 执行哪个对象的方法,由对象的实际类型决定
        demo.overloadFunction(p); // 执行对象的哪个方法,由参数对象的声明类型决定
    }

    public static class ParentClass {
        public void f() {
            System.out.println("I am ParentClass's f().");
        }
    }

    public static class ChildClass extends ParentClass {
        public void f() {
            System.out.println("I am ChildClass's f().");
        }
    }

    public static 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).");
        }
    }
}

执行结果为

I am ChildClass's f().
I am overloadFunction(ParentClass p).

关于代理模式和装饰器模式的一点区别

装饰器类是对功能的增强,这也是装饰器模式应用场景的一个重要特点。实际上,符合“组合关系’这种代码结构的设计模式有很多,比如代理模式、桥接模式,还有现在的装饰器模式。尽管它们的代码结构很相似,但是每种设计模式的意图是不同的。就拿比较相似的代理模式和装饰器模式来说,代理模式中,代理类附加的是跟原始类无关的功能,而在装饰器模式中,装饰器类附加的是跟原始类相关的增强功能。

关于很多设计模式看起来很像的疑惑

实际上,每个设计模式都应该由两部分组成: 第一部分是应用场景,即这个模式可以解决哪类问题; 第二部分是解决方案,即这个模式的设计思路和具体的代码实现。不过,代码实现并不是模式必须包含的。如果你单纯地只关注解决方案这一部分,甚至只关注代码实现,就会产生大部分模式看起来都很相似的错觉。
实际上,设计模式之间的主要区别还是在于设计意图,也就是应用场景。单纯地看设计思路或者代码实现,有些模式确实很相似,比如策略模式和工厂模式。

设计模式的应用场景的考虑

如果我们开发的是偏底层的、框架类的、通用的代码,那代码质量就比较重要,因为一旦出现问题或者代码改动,影响面就比较大。相反,如果我们开发的是业务系统或者不需要长期维护的项目,那稍微放低点代码质量的要求,也是没问题的,而且,自己的代码跟其他项目没有太多耦合,即便出了问题,影响也不大。

posted @ 2024-03-10 21:12  strongmore  阅读(28)  评论(0编辑  收藏  举报