“多态”一次源于希腊文polymorphism,拆开来看是poly(复数) + morph(形态) + ism,从字面上可以理解为复数形态。
多态的实际含义是:统一操作作用于不同的对象上面,可以产生不同的解释和不同的执行结果。换句话说,给不同的对象发送同一个消息的时候,这些对象会根据这个消息分别给出不同的反馈。从字面上理解不太容易,下面举一个例子说明一下。
主人家里养了两只动物,分别是一只鸭和一只鸡,当主人向他们发出“叫”的命令的时候,鸭会“嘎嘎嘎”地叫,鸡会“咯咯咯”地叫。它们同样是动物,并且可以发出叫声,但根据主人的命令,发出的叫声是不同的。这里面就蕴含了多态的思想。

一段”多态”的js代码

把上面的故事用代码来实现:

1
2
3
4
5
6
7
8
9
10
11
12
var makeSound = function( animal ) {
if ( animal instanceof Duce ) {
console.log( '嘎嘎嘎' );
} else if (animal instanceof Chicken ) {
console.log( '咯咯咯' );
}
};
var Duck = function(){};
var Chicken = function(){};
makeSound( new Duck() ); // 嘎嘎嘎
makeSound( new Chicken() ); // 咯咯咯

这段代码确实提现了“多态性”,当发出叫唤的消息的时候,它们各自能作出不同的反应。但是这样的多态性是无法令人满意的,如果后来又增加了一个动物,比如狗,显然狗的叫声是“汪汪汪”,此时我们必须改动makeSound函数,才能让狗发出叫声。修改代码总是不好的,而且当动物的种类越来越多,那么makeSound函数将变得非常巨大。

多态的思想

多态的思想是将“做什么”和“谁去做以及怎么去做”分离开来,也就是将“不变的事物”和“可能改变的事物”分离开来。这个故事中,动物会叫这是不变的,但是不同的动物叫声不同这个是可变的。我们可以把不变的部分分隔开来,然后把可变的部分封装起来,这让我们更好的去扩展程序,也符合开放-封闭原则。

对象的多态性

这是改动后的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
var makeSound = function( animal ) {
animal.sound();
};
var Duck = function(){};
Duck.prototype.sound = function() {
console.log( '嘎嘎嘎' );
};
var Chicken = function(){};
Chicken.prototype.sound = function() {
console.log( '咯咯咯' );
};
makeSound( new Duck() ); // 嘎嘎嘎
makeSound( new Chicken() ); // 咯咯咯

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

Martin Flowler在《重构:改善既有代码的设计》中写道:

多态的最根本好处在于,你不必再向对象询问“你是什么类型”后根据得到的答案调用对象的某个行为—你只管调动该行为就是了,其他的一切多态机制都会为你安排妥当。

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