JavaScript設計模式 - 策略模式

策略模式: 定義一系列算法,把他們一個一個封裝起來,而且使他們能夠相互替換(具備相同的目標和意圖)
示例
我是 div

策略模式指的是定義一些列的算法,把他們一個個封裝起來,目的就是將算法的使用與算法的實現分離開來。
以策略模式的思路實現上邊例子的效果的js代碼:
1. 首先封裝移動節點的緩動算法
 1 /*
 2  * 緩動算法: 接收4個參數,分別表示: 動畫已消失的時間, 小球原始位置, 小球目標位置, 動畫持續的總時間
 3  */
 4 var tween = {
 5     linear: function(t, b, c, d){
 6         return c*t/d + b;
 7     },
 8     easeIn: function(t, b, c, d){
 9         return c * ( t /= d ) * t + b;
10     },
11     strongEaseIn: function(t, b, c, d){
12         return c * ( t /= d ) * t * t * t * t + b;
13     },
14     strongEaseOut: function(t, b, c, d){
15         return c * ( ( t = t / d -1 ) * t * t * t * t + 1 ) + b;
16     },
17     sineaseIn: function(t, b, c, d){
18         return c * ( t /= d ) * t * t + b;
19     },
20     sineaseOut: function(t, b, c, d){
21         return c * ( ( t = t / d -1 ) * t * t + 1 ) +b;
22     }
23 };
 

  2. HTML 部分javascript

 1     <div style="position: relative;border: 1px solid #ff0000; width: 560px;min-height: 30px">
 2         <div style="position:absolute;background:rgba(0,0,255,.3);width: 60px;line-height: 30px;" id="div">我是 div</div>
 3     </div>
 4     <div>
 5         <label><input type="radio" name="tween" value="linear" checked="checked">linear</label>
 6         <label><input type="radio" name="tween" value="easeIn">easeIn</label>
 7         <label><input type="radio" name="tween" value="strongEaseIn">strongEaseIn</label>
 8         <label><input type="radio" name="tween" value="strongEaseOut">strongEaseOut</label>
 9         <label><input type="radio" name="tween" value="sineaseIn">sineaseIn</label>
10         <label><input type="radio" name="tween" value="sineaseOut">sineaseOut</label><br/>
11         <input type="button" id="btnRun" value="run">
12     </div>
View Code

 

 3. 定義一個構造函數接收一個參數:即將運動起來的dom節點
 1 /*
 2  *    Animate 的構造函數接收一個參數:即將運動起來的 dom 節點。
 3  */
 4 var Animate = function( dom ){
 5     this.dom = dom; // 進行運動的 dom 節點
 6     this.startTime = 0; // 動畫開始時間
 7     this.startPos = 0; // 動畫開始時, dom 節點的位置,即 dom 的初始位置
 8     this.endPos = 0; //
 9     this.propertyName = null; // dom 節點須要被改變的 css 屬性名
10     this.easing = null; // 緩動算法
11     this.duration = null; // 動畫持續時間
12 };
 

 

 4. 啓動方法,負責啓動這個動畫
 1 /*
 2  * 負責啓動運動動畫
 3  */
 4 Animate.prototype.start = function( propertyName, endPos, duration, easing ){
 5     this.startTime = +new Date; // 啓動動畫的時間
 6     this.startPos = this.dom.getBoundingClientRect()[ propertyName ]; // dom 節點的初始位置
 7     this.propertyName = propertyName; // dom 節點須要被改變的 CSS 屬性名
 8     this.endPos = endPos; // dom 節點的目標位置
 9     this.duration = duration; // 動畫的持續時間
10     this.easing = tween[ easing ]; // 緩動算法
11 
12     // 啓動動畫定時器
13     var self = this;
14     var timeId = setInterval(function(){
15         if( self.step() === false){
16             clearInterval(timeId);
17         }
18     },20);
19 };
 

 

  5. 動畫定時器運行的步驟,setp方法,節點運動的每一幀要作的事情
/*
 * step 表示節點運動的每一幀要作的事情。 負責計算節點的當前位置和調整更新 CSS 屬性值
 */
Animate.prototype.step = function(){
    var t = +new Date; // 取得當前時間
    if( t >= this.startTime + this.duration){ // 若是動畫結束
        this.update( this.endPos ); // 更新節點的 CSS 屬性
        return false;
    }
    var pos = this.easing( t - this.startTime, this.startPos, this.endPos - this.startPos, this.duration);
    // pos 爲節點當前位置
    this.update( pos ); // 更新節點的 CSS 屬性
};
 

 

 6. 更新節點的CSS屬性值
1 /*
2  * 負責更新節點 CSS 屬性值
3  */
4 Animate.prototype.update = function(pos){
5     this.dom.style[ this.propertyName ] = pos + "px";
6 };
 

 

 7. 測試運行
    /*
     * 建立要運動的節點
     */
    var div = document.getElementById("div");
    var animate = new Animate(div);
    // 設置運行事件
    var btnRun = document.getElementById("btnRun");
    var radios = document.getElementsByName("tween"); // 獲取單選框
    btnRun.onclick = function(){
        for(var i= 0,lengh=radios.length;i<lengh;i++){
            // 查找被選中要執行的算法策略
            if(radios[i].checked){
                animate.reset(); // 重置節點運動屬性
                // 設置動畫的基本屬性
                animate.start( "left", 500, 1000, radios[i].value);
                break;
            }
        }
    };
 

 

 8. 重置節點的CSS屬性爲0,reset()方法
Animate.prototype.reset = function(){
        // 重置爲 0
    this.dom.style[this.propertyName] = "0px";
};
 

 

策略模式總結:
策略模式的優勢:
  1. 策略模式利用組合、委託和多態等技術和思想,能夠有效地避免多重條件選擇語句
  2. 策略模式提供了對開放-封閉原則的完美支持,將算法封裝在獨立的 strategy 中,使得它們易於切換,易於理解,易於擴展
策略模式的缺點:
  1. 會在程序中增長許多策略類或者策略對象,但實際上比把他們負責的邏輯堆砌在 Context 中要好
  2. 使用策略模式,必須瞭解全部的策略,才能更好的選擇一個合適的策略

閱讀參考書籍 - << JavaScript 設計模式與開發實踐 >>
緩動算法 - javascript Tween算法及效果
相關文章
相關標籤/搜索