关于javascript:设计模式之策略模式

25次阅读

共计 5961 个字符,预计需要花费 15 分钟才能阅读完成。

1、策略模式定义:

将一系列算法封装起来,为了当前能够相互替换应用,由策略类和 context 组成,context 承受用户信息,而后将申请委托给策略类
(现实生活中,咱们要去一个城市,交通形式就有:飞机、高铁、开车、大巴等,这些形式都能达到目的地,咱们能够依据本身需要来抉择一个策略)

2、策略模式的长处

1. 策略模式利用组合、委托和多态等技术思维,能够无效的防止许多重条件抉择语句
2. 有弹性,恪守关闭 / 开发准则,将算法封装在独立的 strategy 中,使他易于切换、易于了解、易于扩大
3. 复用不便
4. 利用委托和组合来让 context 领有执行算法的能力,这也是继承的一种更轻便的代替计划 

3、策略模式的毛病

1. 会产生比拟多的类和函数
2. 要应用策略就要明确所有策略,违反常识起码化准则 

4、通过策略模式学习播种到什么

1. 封装变动、多态、委托 

5、通过例子来加深策略模式的意识

1. 奖金的计算
  <script>
// /////////////////////////////////// 没有应用策略模式 /////////////////////////////////////////
        
        function cuculateBounds(leave,salary){if(leave==="A"){return 4*salary}else if(leave ==="B"){return 3*salary}else{return 2*salary}
        }
// console.log(cuculateBounds("A",3000))
// console.log(cuculateBounds("B",3000))
// 毛病:// 1、所有逻辑都在 cuculateBounds 函数体外面,要蕴含所有的 if-else,体量宏大
// 2、不足弹性,如果要批改奖金等级 A 的系数为 3.5,就要扭转函数体,违反关闭凋谢与准则
// 3、复用性差,如果要复用则要用复制粘贴

// /////////////////////////////////// 用策略模式改写 /////////////////////////////////////////
// 1. 将应用算法和算法离开, 应用算法的形式不会变, 算法会变, 所以封装算法 (封装变动)
// 2. 策略类 - 不同策略返回不同后果 (多态)
var strateies={"A":function(salary){return 4*salary;},
    "B":function(salary){return 3*salary;},
    "C":function(salary){return 2*salary;}
}
// 3.context 应用算法, 接管申请, 不执行操作, 将申请委托给策略类 (委托)
var caculateBounds = function(leave,salary){return strateies[leave](salary);
}
console.log(caculateBounds("A",2000))
2. 动画的实现
    <div id="box" style="position:absolute;width: 200px;height: 200px;background-color: cornflowerblue;"></div>
    <script>
        // /////////////////////1. 策略类 - 封装动画缓动算法 /////////////////////
        /**params
         *
         * 开始地位
         * 要挪动的间隔
         * 耗费了多少工夫
         * 总耗时
         *  */
        var easing={"linear":function(starPos,pos,time,duration){return pos*time/duration + starPos;},
            "easeIn":function(starPos,pos,time,duration){return pos*(time/=duration)*time +starPos;
            }
        }
        // /////////////////////2. 动画类 /////////////////////////////////
        // 利用定时器, 没 19 毫秒一帧, 更新 dom 节点款式
        function Animate(dom){this.dom = dom ;}
        // 接管 4 个参数
        /**
         * 款式
         * 挪动指标地位
         * 执行工夫
         * 缓动类型
         * **/
        Animate.prototype.start = function(propety,pos,duration,estype){
            this.propety = propety;
               // 开始地位
            this.startPos = this.dom.getBoundingClientRect()[propety]
            this.endPos = pos;
            this.startTime = +new Date;
            this.endTime = this.startTime+duration;
            this.duraPos = pos-this.startPos;
            this.easing = easing[estype];
            this.duration = duration;
            var _that = this;
           var timeId =  setInterval(()=>{if(_that.step()===false){
                    // 清空定时器
                    clearInterval(timeId)
                    timeId = null;
                }
            },19)

        }
        Animate.prototype.step = function(){
            // 以后工夫大于完结工夫, 返回 false
            var nowTime =+new Date
            if(nowTime>=this.endTime){
                  // 校对地位
                this.update(this.endPos)
                return false
            }else{let pos =   this.easing(this.startPos,this.duraPos,nowTime-this.startTime,this.duration) 
               this.update(pos)
            }

        }
        Animate.prototype.update =function(val){this.dom.style[this.propety] = val+'px'
        }
        // /////////////////////////////3. 调用动画 ////////////////
        var dom  = document.getElementById("box");
        var animate = new Animate(dom);
        // animate.start("top",500,3000,"linear")
        // animate.start("left",500,2000,"easeIn")
        animate.start("left",500,2000,"linear")
        
    </script>
3. 验证表单
    <form id="formpane">
        用户名:<input type="text" value=""id="userName"placeholder=" 请输出 " />
        手机号:<input type="tel" value=""id="telphoneNum" />
        明码:<input type="password" value=""id="userPassword" />
        <button type="submit"> 提交 </button>
    </form>
    <script>
        // 多规定验证,满足条件,表单放行
        /** 多规定验证,满足条件,表单放行
         * 规定 1:用户名不能为空
         * 规定 2:手机格局正确
         * 规定 3:明码长度小于 6
        */
        let regisform = document.getElementById("formpane");
        ///////////////////////// 没有策略模式写法 (我的常见写法)//////////////////

        // regisform.onsubmit = function(){
        //     // 用户名不能为空
        //     if(regisform.userName.value.length===0){//         console.log("用户名不能为空")
        //         return false
        //     }
        //     else if(!/(^1[3|5|8][0-9]{9}$)/.test(regisform.telphoneNum.value)){//         console.log("手机格局不正确")
        //         return false
        //     }else if(regisform.userPassword.value.length>6){
        //         // 明码长度小于 6
        //         console.log("明码长度小于 6")
        //         return false
        //     }
        //     alert("提交胜利")


        // }
        /** 该写法的启发
         * 1、表单的值能够通过表单的 dom.id(子 id) 例 regisform.userName
         * 2、onsubmit 函数体比拟宏大,蕴含所有的 if-else 逻辑
         * 3、不足弹性,当要批改验证规定时,须要改变外部逻辑,违反关闭凋谢准则
         * 4、不易复用
         */

        // /////////////////////////// 用策略模式改写 ////////////////////
        // 1、创立一个策略类
        var stargeies = {isNameEmpty: function (value, msg) {if (value.length === 0)
                    return msg
            },
            isNumberTrue: function (value, msg) {if (!/(^1[3|5|8][0-9]{9}$)/.test(value)) {return msg}

            },
            isMinlen: function (value, min, msg) {if (value.length < min)
                    return msg
            }
        }
        // 2、创立一个 context 的类用来接管用户的申请
        function Invalidator() {this.catchs = [];

        }
        // 增加规定
        Invalidator.prototype.add = function (dom, rules, msg) {var arr = rules.split(":");

            this.catchs.push(function () {let starge = arr.shift();// 删除数组第一个
                let value = dom.value;
                arr.unshift(value);// 在数组第一个插入
                arr.push(msg)
                return stargeies[starge].apply(dom, arr);

            })

        }

        // 执行规定返回后果
        Invalidator.prototype.start = function () {
            // 这种形式遍历,当满足条件,退出循环
            for (let index = 0; index < this.catchs.length; index++) {console.log(index);
                let msg = this.catchs[index]();
                if (msg) {return msg}

            }

        }

        // 3、用户调用规定,依据后果判断是否提交表单
        // var invaliFunc = function(){//     var invalidator = new Invalidator();
        //     invalidator.add(regisform.userName,"isNameEmpty","用户名不能为空");
        //     invalidator.add(regisform.telphoneNum,"isNumberTrue","手机格局不正确");
        //     invalidator.add(regisform.userPassword,"isMinlen:8","明码长度不能小于 8");
        //    return invalidator.start();



        // }
        // regisform.onsubmit = function(){// let value = invaliFunc()
        // if(value){//     console.log(value);
        //     return false;
        // }
        // }

        // ////////////////////////////// 策略模式 - 表单验证多规定 //////////////
        // 增加多规定
        Invalidator.prototype.adds = function (dom, arrs) {

            arrs.forEach(element => {let { rules, msg} = element;
                let arr = rules.split(":");
                this.catchs.push(function () {let starge = arr.shift();// 删除数组第一个
                    let value = dom.value;
                    arr.unshift(value);// 在数组第一个插入
                    arr.push(msg)
                    return stargeies[starge].apply(dom, arr);
                })
            });
        }
        var invaliFunc = function () {var invalidator = new Invalidator();
            invalidator.adds(regisform.userName, [{ rules: "isNameEmpty", msg: "用户名不能为空"}, {rules: "isMinlen:6", msg: "用户名不能小于 6"}]);
            invalidator.add(regisform.telphoneNum, "isNumberTrue", "手机格局不正确");
            invalidator.add(regisform.userPassword, "isMinlen:8", "明码长度不能小于 8");
            return invalidator.start();}

        regisform.onsubmit = function () {let value = invaliFunc()
            if (value) {console.log(value);
                return false;
            }
        }


    </script>

6、理论场景中应用的高阶函数实现隐形的策略模式

    <!-- 常见的策略模式。不会有策略类来寄存策略办法 -->
    <script>
     function planA(params) {console.log("A"+params)
    }
    function planB(params) {console.log("B"+params)
    }
    function planC(params) {console.log("C"+params)
    }
    // 应用高阶函数的形式,参数传入函数,而后将事件委托到策略类中执行,多态,调用这个办法传入不同状态,返回不同后果
    function caculateBounds(func,params){func(params)
    }
    caculateBounds(planA,"欢送应用 A 策略")
    </script>

正文完
 0