再一次,javascript设计模式与开发实践-单一职责原则

定义

如果我们有两个动机去改写一个方法,那么这个方法就具有两个职责。
每个职责都是变化的一个轴线,如果一个方法承担了过多的职责,那么在需求变化的过程中,需要改写这个方法的可能性就越大。
因此,单一职责(SRP)原则体现为:一个对象(方法)只做一件事。

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var createLayer = (function () {
    var div;

    return function () {
        if(!div) {
            div = document.createElement('div');
            div.innerHTML = '我是浮动窗';
            document.body.appendChild(div);
        }

        return div;
    };
})();

var layer1 = createLayer();
var layer2 = createLayer();

console.log(layer1 === layer2); // true

上面的代码把生成单例和创建悬浮窗的职责合在了一起,这个两个方法可以独立变化而不相互影响,那么遵守单一职责应该这样写。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
var getSingle = function (fn) {
    var rst;

    return function () {
        return rst || (rst = fn.apply(this, arguments));
    };
};

var createLayer = function () {
    var div = document.createElement('div');

    div.innerHTML = '我是浮动窗';
    document.body.appendChild(div);

    return div;
};

var createIframe = function () {
    var iframe = document.createElement('iframe');

    iframe.src = 'http://g.cn';
    document.body.appendChild(iframe);

    return iframe;
};


var getLayer = getSingle(createLayer);
var layer1 = getLayer();
var layer2 = getLayer();

console.log(layer1 === layer2); // true


var getIframe = getSingle(createIframe);
var iframe1 = getIframe();
var iframe2 = getIframe();

console.log(getIframe === getIframe); // true

何时应该分离职责

要明确的是,并不是所有的职责都应该分离。
一方面,如果随着需求的变化,有两个职责总是同时变化,那么不必分离它们,比如ajax的时候,创建xhr对象和发送xhr对象的请求几乎总是一起的,那么没有必要分开。

违反单一职责原则

一方面我们受设计原则的指导,另一方面我们未必要在任何时候都一成不变的遵守原则而。
在实际开发中,因为种种原因违反原则的情况并不少见,例如jquery的attr方法,jquery的attr方法是一个很庞大的方法,既负责赋值,又负责取值,这对维护者来说会带来一定的困难,但对使用jquery的用户来说,却简化了使用。
在这方面,没有标准答案。

优缺点

优点是降低了单个类或对象的复杂度,方便了复用和测试,修改时也不会影响到其他职责。
缺点是增加了编写代码的复杂度,当我们按照职责把对象分解成更小的颗粒之后,实际上也增大了对象之间相互联系的难度。