1. 程式人生 > >javascript實現23種設計模式

javascript實現23種設計模式

1. 單例模式

全域性唯一例項

var singleton = function( fn ){
    var result;
    return function(){
        return result || ( result = fn .apply( this, arguments ) );//fn.apply相當於直接呼叫函式,只是將函式內的this(上下文)改變了
    }
}

var createMask = singleton( function(){

return document.body.appendChild( document.createElement('div'
) ); })

2. 簡單工廠模式

//basketball base class  
var Baseketball = function(){  
  this.intro = 'baseketball is hotting at unitedstates';  
}  
Baseketball.prototype = {  
  getMember : function(){\  
    console.log('each team needs five players');  
  },  
  getBallSize : function(){  
    console.log('basketball is big'
); } } //football base class var Football = function(){ this.intro = 'football is popular at all of the world'; } Football = function(){ getMember = function(){ }, getBallSize = function(){ } } //sport factory var SportsFactory = function(name){ switch(name){ case
'NBA': return new Baseketball(); case 'wordCup': return new Football(); } } //when you want football var football = SportsFactory('wordCup'); console.log(football); console.log(football.intro); football.getMember();

三 觀察者模式(釋出者-訂閱者模式 )

面試者把簡歷扔到一個盒子裡, 然後面試官在合適的時機拿著盒子裡的簡歷挨個打電話通知結果.(有任何一個事件發生,所有訂閱者都會通知,只是匹配不上不執行)

Events = function() {

           var listen, log, obj, one, remove, trigger, __this;

           obj = {};

           __this = this;

           listen = function( key, eventfn ) {  //把簡歷扔盒子, key就是聯絡方式.

             var stack, _ref;  //stack是盒子

             stack = ( _ref = obj[key] ) != null ? _ref : obj[ key ] = [];

             return stack.push( eventfn );

           };

           one = function( key, eventfn ) {

             remove( key );

             return listen( key, eventfn );

           };

           remove = function( key ) {

             var _ref;

             return ( _ref = obj[key] ) != null ? _ref.length = 0 : void 0;

           };

           trigger = function() {  //面試官打電話通知面試者

             var fn, stack, _i, _len, _ref, key;

             key = Array.prototype.shift.call( arguments );

             stack = ( _ref = obj[ key ] ) != null ? _ref : obj[ key ] = [];

             for ( _i = 0, _len = stack.length; _i < _len; _i++ ) {

               fn = stack[ _i ];

               if ( fn.apply( __this,  arguments ) === false) {

                 return false;

               }

             }

             return {

                listen: listen,

                one: one,

                remove: remove,

                trigger: trigger

             }

           }

//訂閱者

var adultTv = Event();

adultTv .listen(  ''play',  function( data ){

   alert ( "今天是誰的電影" + data.name );

});

//釋出者

adultTv .trigger(  ''play',  { 'name': '麻生希' }  )

4. 介面卡模式

介面卡模式的作用很像一個轉介面. 本來iphone的充電器是不能直接插在電腦機箱上的, 而通過一個usb轉介面就可以了.-

$id = function( id ){

  return jQuery( '#' + id )[0];

}

5. 代理模式

代理模式的定義是把對一個物件的訪問, 交給另一個代理物件來操作.

舉一個例子, 我在追一個MM想給她送一束花,但是我因為我性格比較靦腆,所以我託付了MM的一個好朋友來送。

6. 橋接模式

橋接模式的作用在於將實現部分和抽象部分分離開來, 以便兩者可以獨立的變化。

7. 外觀模式

外觀模式提供一個高層介面,這個介面使得客戶端或子系統更加方便呼叫。簡單講,就是將小的api封裝成大的api

var stopEvent = function( e ){   //同時阻止事件預設行為和冒泡
  e.stopPropagation();
  e.preventDefault();
}

8. 訪問者模式

訪問者模式先把一些可複用的行為抽象到一個函式(物件)裡,這個函式我們就稱為訪問者(Visitor)。如果另外一些物件要呼叫這個函式,只需要把那些物件當作引數傳給這個函式,在js裡我們經常通過call或者apply的方式傳遞this物件給一個Visitor函式.

var Visitor = {}
Visitor .push  =  function(){
    return Array.prototype.push.apply( this, arguments );
}
var obj = {};
obj.push = Visitor .push;
obj.push( '"first" );
alert ( obj[0] )  //"first"
alert ( obj.length );  //1

9.策略模式

策略模式的意義是定義一系列的演算法,把它們一個個封裝起來,並且使它們可相互替換。
一個小例子就能讓我們一目瞭然。

$( div ).animate( {"left: 200px"}, 1000, 'linear' );  //勻速運動
$( div ).animate( {"left: 200px"}, 1000, 'cubic' );  //三次方的緩動

10. 模版方法模式

模式方法是預先定義一組演算法,先把演算法的不變部分抽象到父類,再將另外一些可變的步驟延遲到子類去實現。實現思路就是繼承,覆蓋父類方法

Mammal.prototope.出生 = function(){
  '胎生()
}
Mammal.prototype.成長 = function(){
  //再留給子類去實現
}
Mammal.prototope.衰老 = function(){
  自由基的過氧化反應()
}
Life.prototype.死亡 = function(){
 //再留給子類去實現
}
//再實現一個Dog類
var = Dog = function(){
}
//Dog繼承自哺乳動物.
Dog.prototype = Mammal.prototype;
var dog = new Dog();
dog.init();

12. 迭代器模式

迭代器模式提供一種方法順序訪問一個聚合物件中各個元素,而又不需要暴露該方法中的內部表示。
js中我們經常會封裝一個each函式用來實現迭代器。
array的迭代器:

forEach = function( ary, fn ){  for ( var i = 0, l = ary.length; i < l; i++ ){    var c = ary[ i ];    if ( fn.call( c, i , c ) === false ){      return false;    }   }}
forEach( [ 1, 2, 3 ], function( i, n ){
  alert ( i );
})

13.組合模式

又叫部分-整體模式,它將所有物件組合成樹形結構。使得使用者只需要操作最上層的介面,就可以對所有成員做相同的操作。
form.validata函式, 它負責把真正的validata操作分發給每個組合物件.
form.validata函式裡面會依次遍歷所有需要校驗的field. 若有一個field校驗未通過, form.validata都會返回false. 虛擬碼如下.

form.validata = function(){
  forEach( fields, function( index, field ){
    if ( field.validata() === false  ){
       return false;
    }
  })
  return true;
}

14. 備忘錄模式

備忘錄模式在js中經常用於資料快取. 比如一個分頁控制元件, 從伺服器獲得某一頁的資料後可以存入快取。以後再翻回這一頁的時候,可以直接使用快取裡的資料而無需再次請求伺服器。
實現比較簡單,虛擬碼:

var Page = function(){
   var page = 1,
      cache = {},
      data;
   return function( page ){
      if ( cache[ page ] ){
               data =  cache[ page ];
               render( data );
      }else{
               Ajax.send( 'cgi.xx.com/xxx', function( data ){
                   cache[ page ] = data;
                   render( data );
               })
      }
    }
}()

15. 職責鏈模式

js中的事件冒泡就是作為一個職責鏈來實現的。一個事件在某個節點上被觸發,然後向根節點傳遞, 直到被節點捕獲。

16. 享元模式

享元模式可以提供一些共享的物件以便重複利用. 仔細看下上圖, 其實我們一共只需要10個div來顯示好友資訊,也就是出現在使用者視線中的10個div.這10個div就可以寫成享元.

 var getDiv = (function(){
    var created = [];
    var create = function(){
          return document.body.appendChild( document.createElement( 'div' ) );
    }
    var get = function(){
         if ( created.length ){
              return created.shift();
          }else{
                return create();
           }
     }
/* 一個假設的事件,用來監聽剛消失在視線外的div,實際上可以通過監聽滾                                     動條位置來實現 */
      userInfoContainer.disappear(function( div ){
              created.push( div );
        })
 })()
  var div = getDiv();
  div.innerHTML = "${userinfo}";

17. 狀態模式

通過這個狀態類,可以把散落在世界各地的條件分支集中管理到一個類裡,並且可以很容易的新增一種新的狀態。而作為呼叫者,只需要通過暴露的changeState介面來切換人物的狀態。

var StateManager = function(){
  var currState = 'wait';
  var states = {
    jump: function( state ){
    },
    wait: function( state ){
    },
    attack: function( state ){
    },
    crouch: function( state ){
    },
    defense: function( state ){
      if ( currState === 'jump'  ){
          return false;  //不成功,跳躍的時候不能防禦
      }
    //do something;     //防禦的真正邏輯程式碼, 為了防止狀態類的程式碼過多, 應該把這些邏輯繼續扔給真正的fight類來執行.
    currState = 'defense'; //  切換狀態
    }
  }
  var changeState = function( state ){
    states[ state ] && states[ state ]();
  }
  return {
      changeState  : changeState
  }
}
var stateManager = StateManager();
stateManager.changeState( 'defense' );