设计模式之-策略模式

码影漫游家
• 阅读 901

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>
点赞
收藏
评论区
推荐文章
Easter79 Easter79
3年前
Vue 骚技巧,策略模式实现动态表单验证
!(https://oscimg.oschina.net/oscnet/5e0568a314054f2d995c1562bda18f70.png)策略模式(StrategyPattern)又称政策模式,其定义一系列的算法,把它们一个个封装起来,并且使它们可以互相替换。封装的策略算法一般是独立的,策略模式根据输入来调整采用哪个算法。
Easter79 Easter79
3年前
spring中策略模式使用
策略模式工作中经常使用到策略模式工厂模式,实现一个接口多种实现的灵活调用与后续代码的扩展性。在spring中使用策略模式更为简单,所有的bean均为spring容器管理,只需获取该接口的所有实现类即可。下面以事件处理功能为例,接收到事件之后,根据事件类型调用不同的实现接口去处理。如需新增事件,只需扩展实现类即可,无需改动之前的代码。这样即
Wesley13 Wesley13
3年前
Java设计模式
一、策略模式(让算法与对象独立)    策略模式定义了算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。!(http://static.oschina.net/uploads/space/2016/1108/180244_oYm8_1789589.png)二、观察者模式(让你的对象知悉现状) 
Wesley13 Wesley13
3年前
Java 设计模式系列(十二)策略模式(Strategy)
Java设计模式系列(十二)策略模式(Strategy)策略模式属于对象的行为模式。其用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。一、策略模式的结构策略模式是对算
Wesley13 Wesley13
3年前
Java23种设计模式案例:策略模式(strategy)
  现实生活中,我们要做一件事情或者完成某项工作,往往有很多种途径。比如我们出游,可以选择坐汽车,坐火车,土豪点的选择是坐飞机。还有我们现在线下的支付方式也有了很多种选择,以前在外面忘了带钱的话可能一瓶水都难以买到,现在只要我们手机在身上,可以用微信或者支付宝。  在软件设计层面,我们把各种支付方式叫做策略。如果不考虑设计模式的话,我们可能会在一个类中用
Wesley13 Wesley13
3年前
如何利用策略模式避免冗长的 if
策略模式。在实际的项目开发中,这个模式也比较常用。最常见的应用场景是,利用它来避免冗长的ifelse或switch分支判断。不过,它的作用还不止如此。它也可以像模板模式那样,提供框架的扩展点等等。对于策略模式。本篇我们讲解策略模式的原理和实现,以及如何用它来避免分支判断逻辑。后续我会通过一个具体的例子,来详细讲解策略模式的应用场景以及真正的设计意图
Wesley13 Wesley13
3年前
IO完全手册汇总
InputSream,一级子类8个,1个抽象类FilterInputStream.二级策略模式FilterInputStream下9个\其中一个过时\.1个抽象类InflaterInputStream.三级策略模式InflaterInputStream下2个.java.io.ByteArrayInputStream 使用场
京东云开发者 京东云开发者
2个月前
设计模式-策略模式
作者:京东工业孙磊一、概念策略模式(StrategyPattern)也称为(PolicyParttern)。它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变换,不会影响到使用算法的客户。策略模式属性行为模式。策略模式结构图\二、实际
设计模式之策略模式:让你的代码灵活应对不同的算法 | 京东云技术团队
作为一个程序员,我们经常会面临着在不同的情况下选择不同的算法来解决问题的需求。这种情况下,策略模式是一个非常有用的设计模式。在本文中,我将向你介绍策略模式的概念、结构以及如何应用这个模式来使你的代码更灵活。
京东云开发者 京东云开发者
7个月前
设计模式-策略模式
作者:京东工业孙磊一、概念策略模式(StrategyPattern)也称为(PolicyParttern)。它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变换,不会影响到使用算法的客户。策略模式属性行为模式。策略模式结构图\二、实际
京东云开发者 京东云开发者
3个月前
设计模式-策略模式
作者:京东工业孙磊一、概念策略模式(StrategyPattern)也称为(PolicyParttern)。它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变换,不会影响到使用算法的客户。策略模式属性行为模式。策略模式结构图\二、实际
码影漫游家
码影漫游家
Lv1
浪漫世界值得孤身。
文章
4
粉丝
0
获赞
0