javascript的设计模式(二)———— 设计模式原则

一般来说,设计模式拥有六个原则:单一职责原则、里氏替换原则、依赖倒置原则、接口隔离原则、迪米特法则和开闭原则。然而js中没有抽象、继承、接口这些定义,故在《javascript设计模式与开发实践》一书中只提到了单一职责原则、最少知识原则(迪米特法则)和开闭原则。

正文

1.单一职责原则

单一职责,顾名思义就是一个方法只做一件事。这很容易理解,也可以看看下面这段代码:
//未遵循单一职责,将创建div和单例检测两个功能放在了一起
var createDiv = (function(){
  var div;
  return function(){
    if(!div){  //单例职责
      div = document.createElement('div');  //创建div
      document.body.appendChild(div);
    }
    return div;
  }
})()

//遵循单一职责
var createSingle = function(fn){  //单例职责
  var result;
  return function(){
    return result || (result = fn.apply(this, arguments));
  }
}
var createDiv = function(){  //创建div
  var div = document.createElement('div');
  document.body.appendChild(div);
  return div;
}

var createSingleDiv = createSingle(createDiv);

var div1 = createSingleDiv();
var div2 = createSingleDiv();

console.log(div1 === div2); //true;
从上面是一段单例模式的代码,很清晰的表达了单一原则的意思:一个方法只做一件事。当需要修改时,程序员不需要从一大段代码中找出对应功能的代码,而且很重要的是你不能保证修改的代码没有影响到另一个功能,一旦出现bug查找起来就会非常麻烦,遵循单一原则对于代码的维护有着非常重要的作用。
但是单一原则的使用,一定程度上会增加代码的量。一般来说,当若干个代码的改变是同时进行的(就像websocket的connect和open几乎是一起执行的),那么就可以忽略单一原则,把他们写在一起更方便维护。

2.最少知识原则

最少知识原则,说白了就是对象之间的解耦,两个对象之间尽量减少内部的交流。一般的实现方法有:委托第三方(中介者模式等)和封装暴露接口调用。

2.1封装

封装广义来说包括封装数据、封装实现、封装类型和封装变化。对于js来说并无类型限制,所以封装类型先忽略。
封装数据,其实就是对变量、函数的作用域进行限制,实现类似java中的sectionublish和private。如下实现:
```javascript function createDiv = function(){ var div; //div的作用域就被限制在createDiv里面,变成了createDiv的私有变量。 return function(){ //这个方法就被曝光给外作用域使用。 div = document.createElement('div'); document.body.appendChild(div);
return div;

}
}

<section></section>

#### 2.2封装变化
<section>将对象中变化的部分抽取出来进行封装,这样在替换变化部分的时候就不会影响到不变化的部分。</section>
#### 2.3封装实现

封装的目的就是将信息隐藏,是的对象内部的变化对其他对象是透明的,也就是不可见的。对象对自己的行为负责,对象之间通过暴露出来的API进行通信。

### 3.开闭原则
<p>开闭原则,就是使程序拥有扩展性,当要修改或要增加一段代码时,不必要在原来的代码上做修改。下面来介绍一下实现开闭原则的几种方式</p>

#### 3.1职责链模式
```javascript
Function.prototype.after = function(fn){
  var _ = this;
  return function(){
    var ret = _.apply(this, arguments);
    fn.apply(this, arguments);
    return ret;
  }
}

Function.prototype.before = function(fn){
	var _ = this;
	return function(){
    fn.apply(this, arguments);
    return _.apply(this, arguments);
  }
}

window.onload = function(){
  console.log('load2');
}

....//一系列代码

window.onload = (window.onload || function(){}).after(function(){ //在window.onload事件中添加别的行为,而不会覆盖原来的行为
	console.log('load3');
}).before(function(){
  console.log('load1');
})

//结果: load1
//      load2
//      load3

上面的代码使window.onload有了扩展性,在后面添加的方法并不会覆盖前面定义的代码,而是可以一并实行。把after和before两个方法用在其他方法中也是一样的,如此以来程序员在未来要添加方法的时候就不必要跑到原来的方法中修改代码,就可以避免不必要的bug发生。

3.2对象多态

可以参考上一篇博客《javascript的设计模式(一)———— 多态》

3.3回调函数

var createDiv = function(cb){
  var div = document.createElement('div');
  cb && cb();
}

createDiv(function(){
  console.log('create success');
})

//create success

开闭原则一般来说很难100%的实现,作为程序员我们应该尽量把会发生改变的地方单独出来,方便修改。在第一次些代码的时很少可以考虑完善哪些地方需要修改,所以在着手写代码时可以先不考虑开闭原则,在后来需求比较确定之后再进行代码的完善。

posted @ 2017-08-08 17:39  Marys  阅读(232)  评论(0)    收藏  举报