1473 字
7 分钟
多态

多态的实际含义是:同一操作作用于不同的对象上面,可以产生不同的解释和不同的执行结 果。换句话说,给不同的对象发送同一个消息的时候,这些对象会根据这个消息分别给出不同的 反馈。

var makeSound = function (animal) {
if(animal instanceof Duck){
console.log('嘎嘎嘎');
}else if(animal instanceof Dog){
console.log('汪汪');
}
}
var Duck = function(){};
var Dog = function(){};
makeSound(new Duck());
makeSound(new Dog());

​ 这段代码确实体现了“多态性”,当我们分别向鸭和鸡发出“叫唤”的消息时,它们根据此 消息作出了各自不同的反应。但这样的“多态性”是无法令人满意的,如果后来又增加了一只动 物,比如狗,显然狗的叫声是“汪汪汪”,此时我们必须得改动 makeSound 函数,才能让狗也发出 叫声。修改代码总是危险的,修改的地方越多,程序出错的可能性就越大,而且当动物的种类越 来越多时, makeSound 有可能变成一个巨大的函数。

​ 多态背后的思想是将“做什么”和“谁去做以及怎样去做”分离开来,也就是将“不变的事 物”与 “可能改变的事物”分离开来。在这个故事中,动物都会叫,这是不变的,但是不同类 型的动物具体怎么叫是可变的。把不变的部分隔离出来,把可变的部分封装起来,这给予了我们 扩展程序的能力,程序看起来是可生长的,也是符合开放 — 封闭原则的,相对于修改代码来说, 仅仅增加代码就能完成同样的功能,这显然优雅和安全得多

1. 对象的多态性#

var makeSound = function (animal) {
if (typeof animal === 'object' && animal.sound) {
animal.sound();
} else {
console.log('我不是动物我不能叫')
}
}
var Duck = function () { };
var Dog = function () { };
Duck.prototype.sound = function () {
console.log('嘎嘎嘎嘎');
}
makeSound(new Duck());
makeSound(new Dog());

2. JavaScript的多态#

多态的思想实际上是把“做什么”和“谁去做”分离开来,要实现这一点,归根结底先要消除类型之间的耦合关系。如果类型之间的耦合关系没有被消除,那么我们在 makeSound 方法中指定了发出叫声的对象是某个类型,它就不可能再被替换为另外一个类型。

在 Java中,可以通过向上转型来实现多态。

而 JavaScript的变量类型在运行期是可变的。一个 JavaScript对象,既可以表示 Duck 类型的 对象,又可以表示 Chicken 类型的对象,这意味着 JavaScript对象的多态性是与生俱来的

这种与生俱来的多态性并不难解释。JavaScript作为一门动态类型语言,它在编译时没有类型 检查的过程,既没有检查创建的对象类型,又没有检查传递的参数类型。

由此可见,某一种动物能否发出叫声,只取决于它有没有 makeSound 方法,而不取决于它是 否是某种类型的对象,这里不存在任何程度上的“类型耦合”。在 JavaScript中,并不需要诸如向上转型之类的技术来取得多态的效果。

3. 多态在面向对象程序设计中的作用#

有许多人认为,多态是面向对象编程语言中最重要的技术。但我们目前还很难看出这一点, 毕竟大部分人都不关心鸡是怎么叫的,也不想知道鸭是怎么叫的。让鸡和鸭在同一个消息之下发 出不同的叫声,这跟程序员有什么关系呢?

Martin Fowler在《重构:改善既有代码的设计》里写到: 多态的最根本好处在于,你不必再向对象询问“你是什么类型”而后根据得到的答 案调用对象的某个行为——你只管调用该行为就是了,其他的一切多态机制都会为你安 排妥当。

换句话说,多态最根本的作用就是通过把过程化的条件分支语句转化为对象的多态性,从而 消除这些条件分支语句。

Martin Fowler的话可以用下面这个例子很好地诠释:

在电影的拍摄现场,当导演喊出“action”时,主角开始背台词,照明师负责打灯 光,后面的群众演员假装中枪倒地,道具师往镜头里撒上雪花。在得到同一个消息时, 每个对象都知道自己应该做什么。如果不利用对象的多态性,而是用面向过程的方式来 编写这一段代码,那么相当于在电影开始拍摄之后,导演每次都要走到每个人的面前, 确认它们的职业分工(类型),然后告诉他们要做什么。如果映射到程序中,那么程序 中将充斥着条件分支语句。

利用对象的多态性,导演在发布消息时,就不必考虑各个对象接到消息后应该做什么。对象 应该做什么并不是临时决定的,而是已经事先约定和排练完毕的。每个对象应该做什么,已经成 为了该对象的一个方法,被安装在对象的内部,每个对象负责它们自己的行为。所以这些对象可 以根据同一个消息,有条不紊地分别进行各自的工作。

将行为分布在各个对象中,并让这些对象各自负责自己的行为,这正是面向对象设计的优点。

多态
https://nollieleo.github.io/posts/多态/
作者
翁先森
发布于
2020-03-16
许可协议
CC BY-NC-SA 4.0