软件实体(类,模块,函数)等应该是可以扩展的,但是不可修改。 当需要改变一个程序的功能或者给这个程序增加新功能时候,可以使用增加代码的方式,但是不允许改动程序的源代码。 反应到程序中时,当我们看到一大片if或者swith-case的语句时,第一时间应该考虑,能够用对象的多态来重构它们。
var Duck = function(){};
var Chicken = function(){};
var makeSound = function(animal){
if(animal instanceof Duck) {
console.log('嘎嘎嘎');
} else if(animal instanceof Chicken) {
console.log('咯咯咯');
}
};
makeSound(new Duck());
makeSound(new Chicken());
上述程序的问题在于,当新增一个动物时,我们不得不修改makeSound函数增加if语句。 解决方法为,利用多态的思想,我们把程序中不变的部分隔离出来(动物都会叫),然后把可变的部分封装起来(不同动物发出不同的叫声),这样一来程序就有可扩展性。
var Duck = function(){};
Duck.prototype.sound = function() {
console.log('嘎嘎嘎');
};
var Chicken = function(){};
Chicken.prototype.sound = function() {
console.log('咯咯咯');
};
var makeSound = function(animal){
animal.sound();
};
makeSound(new Duck());
makeSound(new Chicken());
这样一来即使增加新的动物,那么也不用改变原有的makeSound方法。
遵守开放封闭原则,最明显的就是找出程序中将要发生变化的地方,然后把变化封装起来。通过封装变化的方式,可以把系统中稳定不变的部分和容易变化的部分隔离开。 在系统演变过程中,我们只需要替代那些容易变换的部分,如果这些部分是已经封装好的,那么替换起来相对容易,变化部分之外的就是稳定的部分。 除了利用对象的多态性之外,还有其他方式让我们遵守该原则:
- 放置hook
- 使用回调函数,回调函数是一种特殊的挂钩,我们把一部分易于变化的逻辑疯转在回调函数中,然后把回调函数当做参数传入到一个稳定和封闭的函数中。
var arrayMap = function(array, callback) {
var i = 0,
length = array.length,
value,
ret = [];
for(; i<length; i++ ) {
value = callback(i, array[i]);
ret.push(value);
}
return ret;
}
var a = arrayMap([1, 2, 3], function() {
return n*2;
});
arrayMap函数的作用是把一个数组映射为另外一个数组,映射的步骤是不变的,而映射的规则是可变的,将其放入回调函数中。
- 观察者模式
- 模板方法模式
- 策略模式
- 代理模式