Skip to content

Instantly share code, notes, and snippets.

@simonwoo
Last active November 21, 2016 21:16
Show Gist options
  • Save simonwoo/1d4f291556e991f5ce906530124fd041 to your computer and use it in GitHub Desktop.
Save simonwoo/1d4f291556e991f5ce906530124fd041 to your computer and use it in GitHub Desktop.

定义

软件实体(类,模块,函数)等应该是可以扩展的,但是不可修改。 当需要改变一个程序的功能或者给这个程序增加新功能时候,可以使用增加代码的方式,但是不允许改动程序的源代码。 反应到程序中时,当我们看到一大片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函数的作用是把一个数组映射为另外一个数组,映射的步骤是不变的,而映射的规则是可变的,将其放入回调函数中。

设计模式中该原则的体现

  • 观察者模式
  • 模板方法模式
  • 策略模式
  • 代理模式
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment