Xiao Peng

My personal blog moves to xiaopeng.me , blogs about design patterns will be synced to here.
肖鹏,ThoughtWorks资深咨询师,目前关注于架构模式、敏捷软件开发等领域,并致力于软件开发最佳实践的推广和应用。
多次为国内大型企业敏捷组织转型提供咨询和培训服务,在大型团队持续集成方面具有丰富的经验。
  博客园  :: 首页  :: 联系 :: 订阅 订阅  :: 管理

再说面试-为什么你需要知道多态

Posted on 2007-07-22 23:39  勇敢的鸵鸟  阅读(4763)  评论(27编辑  收藏  举报

也说面试的火爆是让我震惊的。既然标榜为一个有使命感的程序员,我觉得有责任再写一篇关于多态的文字。我无意再次挑起非技术的争议。所以关于也说面试的回复并不包含在本文中。本文是一篇纯技术文字,里面有任何谬误请不吝指出。我思考再三题目中保留了“再说面试”四个字,让整个事情有始有终,因为我说过要写一篇这样的文章。但是阅读的时候请抛开面试这个背景。

我的文章大多枯燥无味我推荐你阅读Allen Lee或者idior的文章,或者Google更多的文章(使用多态或者Polymorphism作为关键字)。

一、什么是多态?

多态是OO中最关键的特性之一(GOF语)。GOF给的定义是:The ability to substitute objects of matching interface for one another at runtime。即,在运行时刻接口匹配的对象能互换的能力。在Wikipedia上则表述为...,polymorphism lets you treat derived class members just like there parent class's members。即,多态使得你可以向对待父类的成员那样对待派生类的成员。不够直观?In practical terms, polymorphism means that if class B inherits from class A, it doesn't have to inherit everything about class A; it can do some of the things that class A does differently。即,如果class B继承自class A,它不必从class A中继承所有的东西;对于某些方法,class B可以采用与class A不同的做法和实现。

在Java和C#的语言机制中,多态表现为后绑定(或者叫动态绑定、晚期绑定),有两种形式:继承父类并重载父类中具有相同签名的方法(即overriding或者overwriting);实现抽象父类(或接口)中具有相同签名的方法。当你对由父类声明的对象调用该方法时,对应的子类中的方法就会被调用。顺便说一句overloading通常不被认为是多态机制。

在OO思想中多态隐藏具体实现,使得客户端在不了解具体实现而只了解其接口的情况下可以访问对象的方法,这使得抽象成为可能。

二、多态和抽象的关系

还是采用Wikipedia的说法吧:abstraction is a mechanism and practice to reduce and factor out details so that one can focus on a few concepts at a time。即,抽象是一种可以使你一次只关注一个事物几个概念的机制和实践。我觉得还是从反面去解释更为简单,抽象就是不具体,就可以抛开你所不关心的细节。

抽象可以使我们对对象进行更好的分类。想象一下,没有抽象,当你面对一个电灯泡的时候会多么的无奈:

  • 它有重量,这一点和石头很相似;
  • 它有体积,这一点和石头也很相似;
  • 它能发光,这一点和太阳很相似;
  • 它耗电,这一点和风扇很相似;
  • 它可以开关,这一点和门很相似。
  • ......

这一切特性都属于灯泡,所以灯泡不是石头、不是太阳、不是风扇也不是门。没有抽象,当你要打算为电灯泡写一个开关的时候,它也只能处理电灯泡对象,因为这个世界上(系统中)没有另一个东西具有电灯泡的所有特性。

有了抽象,世界将会怎样?

  • 你说电灯泡是一个有重量的对象所以它是个Weighable(可称重的),那个用来给石头称重的系统也适用于电灯泡!
  • 你说电灯泡是一个有体积的对象所以它是个Stereometriable(可以求积的),那个用来给石头算体积的系统居然也适用!
  • 你说电灯泡是一个可以开关的对象所以它是个个Switchable(可开关的),那个用来开关门的系统也可以开关电灯泡吧!
    ......现在我们可以为电灯泡的各种特性分类了,从不同的角度看待电灯泡。

这个时候你就发现你的系统对于电灯泡的依赖越来越低了,哪一天电灯泡不发光了(还叫电灯泡:)),你的开关函数居然还是不用重写呢。抽象相对于具体类要稳定,所以依赖于抽象也比依赖于具体类要稳定。

并不是说没有多态就做不到抽象,只是没有多态抽象就很难做得如此优雅。语言机制中的多态为抽象处理了大部分你不希望关心的细节。

三、多态与耦合的关系

耦合的定义:The degree to which software components depend on each other。即软件构件之间相互依赖的程度。当系统耦合越强的时候,系统越僵化、越不容易维护、不容易重用,更糟糕的是耦合越强的系统越不稳定。理论上系统中所有的构件之间都是耦合的,只是耦合的程度不同,所以我们追求解耦合实际上是追求松耦合。这篇文章称松耦合是软件的终极目标,虽然有些过激但是是非常有道理的。

解耦合的方法通常包括抽象耦合和增加层。抽象耦合:既然必须依赖,依赖于抽象总比依赖于具体要松一些(比如Observer模式)。增加层的方法有很多,在OO的机制内可以以委托的方式将部分职能转移到专门的类中(比如将创建职能转移到工厂中),而这个专门的类是一个相对稳定的类;也可以加入一个层隔离与不希望关心的构件的关系(比如Facade模式)。

抽象耦合在上一节已经讲了,与多态有着密切的联系。增加层的方法主要的idea是委托,与多态的关系不大。

太晚了今天先写到这里吧,下面可能加入一些演示多态和耦合的关系的例子,还包括多态和常见的OOD原则的关系,以及可能还会有多态和设计模式的关系。