《JavaScript設計模式與開發實踐》原則篇(1)—— 單一職責原則

單一職責原則(SRP)的職責被定義爲「引發變化的緣由」。若是咱們有兩個動機去改寫一 個方法,那麼這個方法就具備兩個職責。每一個職責都是變化的一個軸線,若是一個方法承擔了過 多的職責,那麼在需求的變遷過程當中,須要改寫這個方法的可能性就越大。 此時,這個方法一般是一個不穩定的方法,修改代碼老是一件危險的事情,特別是當兩個職 責耦合在一塊兒的時候,一個職責發生變化可能會影響到其餘職責的實現,形成意想不到的破壞, 這種耦合性獲得的是低內聚和脆弱的設計。 所以,SRP 原則體現爲:一個對象(方法)只作一件事情。ajax

用到SRP的設計模式

  • 代理模式
    圖片預加載:經過增長虛擬代理的方式,把預加載圖片的職責放到代理對象中,而本體僅僅負責往頁面中添加 img 標籤,這也是它最原始的職責 把添加 img 標籤的功能和預加載圖片的職責分開放到兩個對象中,這兩個對象各自都只有一個被修改的動機。在它們各自發生改變的時候,也不會影響另外的對象
/* myImage 負責往頁面中添加 img 標籤 */
var myImage = (function(){
    var imgNode = document.createElement( 'img' );     
    document.body.appendChild( imgNode );
    return {
        setSrc: function( src ){
            imgNode.src = src; 
        }
    } 
})();
/* proxyImage 負責預加載圖片,並在預加載完成以後把請求交給本體 myImage */
var proxyImage = (function(){ 
    var img = new Image; img.onload = function(){
        myImage.setSrc( this.src ); 
    }
    return {
        setSrc: function( src ){
            myImage.setSrc( 'file:// /C:/Users/svenzeng/Desktop/loading.gif' );
            img.src = src; 
        }
     } 
})();
proxyImage.setSrc('http://imgcache.qq.com/music/photo/000GGDys0yA0Nk.jpg' );
複製代碼
  • 迭代器模式 咱們有這樣一段代碼,先遍歷一個集合,而後往頁面中添加一些 div,這些 div 的 innerHTML分別對應集合裏的元素
var appendDiv = function( data ){
    for ( var i = 0, l = data.length; i < l; i++ ){
        var div = document.createElement( 'div' ); 
        div.innerHTML = data[ i ]; document.body.appendChild( div );
    } 
};
appendDiv( [ 1, 2, 3, 4, 5, 6 ] );
複製代碼

appendDiv 函數原本只是負責渲染數據,可是在這裏它還承擔了遍歷聚合對象 data 的職責設計模式

咱們有必要把遍歷 data 的職責提取出來,這正是迭代器模式的意義,迭代器模式提供了一 種方法來訪問聚合對象,而不用暴露這個對象的內部表示數組

var each = function( obj, callback ) { 
    var value,
    i = 0,
    length = obj.length,
    isArray = isArraylike( obj );
    if ( isArray ) { // 迭代類數組 
        for ( ; i < length; i++ ) {// isArraylike 函數未實現,能夠翻閱 jQuery 源代碼
            callback.call( obj[ i ], i, obj[ i ] ); 
        }
    } else {
        for ( i in obj ) { // 迭代object對象
            value = callback.call( obj[ i ], i, obj[ i ] ); 
        }
    }
    return obj;
};
var appendDiv = function( data ){ 
    each( data, function( i, n ){
        var div = document.createElement( 'div' ); 
        div.innerHTML = n; document.body.appendChild( div );
    }); 
};
appendDiv( [ 1, 2, 3, 4, 5, 6 ] ); 
appendDiv({a:1,b:2,c:3,d:4} );
複製代碼
  • 單例模式 最開始的登陸窗惰性單例
var createLoginLayer = (function(){ 
    var div;
    return function(){ 
        if ( !div ){
            div = document.createElement( 'div' ); 
            div.innerHTML = '我是登陸浮窗'; 
            div.style.display = 'none'; 
            document.body.appendChild( div );
        }
        return div; 
    }
})();
複製代碼

如今咱們把管理單例的職責和建立登陸浮窗的職責分別封裝在兩個方法裏,這兩個方法能夠 獨立變化而互不影響,當它們鏈接在一塊兒的時候,就完成了建立惟一登陸浮窗的功能bash

var getSingle = function( fn ){ // 獲取單例 var result;
    return function(){
        return result || ( result = fn .apply(this, arguments ) );    
    }
};
var createLoginLayer = function(){ // 建立登陸浮窗 
    var div = document.createElement( 'div' ); 
    div.innerHTML = '我是登陸浮窗'; 
    document.body.appendChild( div );
    return div; 
};
var createSingleLoginLayer = getSingle( createLoginLayer );
var loginLayer1 = createSingleLoginLayer(); 
var loginLayer2 = createSingleLoginLayer();
alert ( loginLayer1 === loginLayer2 ); // 輸出: true
複製代碼

何時使用SRP?

一方面,若是隨着需求的變化,有兩個職責老是同時變化,那就沒必要分離他們。好比在 ajax 請求的時候,建立 xhr 對象和發送 xhr 請求幾乎老是在一塊兒的,那麼建立 xhr 對象的職責和發送 xhr 請求的職責就沒有必要分開。 另外一方面,職責的變化軸線僅當它們肯定會發生變化時才具備意義,即便兩個職責已經被耦 合在一塊兒,但它們尚未發生改變的徵兆,那麼也許沒有必要主動分離它們,在代碼須要重構的 時候再進行分離也不遲。app

總結

SRP 原則的優勢是下降了單個類或者對象的複雜度,按照職責把對象分解成更小的粒度, 這有助於代碼的複用,也有利於進行單元測試。當一個職責須要變動的時候,不會影響到其餘的職責。 但SRP 原則也有一些缺點,最明顯的是會增長編寫代碼的複雜度。當咱們按照職責把對象分解成更小的粒度以後,實際上也增大了這些對象之間相互聯繫的難度。函數

系列文章:

《JavaScript設計模式與開發實踐》最全知識點彙總大全post

相關文章
相關標籤/搜索