资讯

精准传达 • 有效沟通

从品牌网站建设到网络营销策划,从策略到执行的一站式服务

JavaScript策略模式如何实现

这篇文章主要介绍“JavaScript策略模式如何实现”,在日常操作中,相信很多人在JavaScript策略模式如何实现问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”JavaScript策略模式如何实现”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

桥西网站制作公司哪家好,找创新互联!从网页设计、网站建设、微信开发、APP开发、成都响应式网站建设公司等网站项目制作,到程序开发,运营维护。创新互联成立于2013年到现在10年的时间,我们拥有了丰富的建站经验和运维经验,来保证我们的工作的顺利进行。专注于网站建设就选创新互联

策略模式:定义了一系列家族算法,并对每一种算法单独封装起来,让算法之间可以相互替换,独立于使用算法的客户。

通常我并不会记得“牛顿***定律”的具体内容,所以我也难保证我会对这个定义记得多久……用FE经常见到的东西来举个例子说明一下:

$("div").animation({left: '50px'},1000,'easein');  $("div").animation({left: '50px'},1000,'linear');  $("div").animation({left: '50px'},1000,'swing');  //看***三个关于动画效果的参数  //Jquery文档总提到easing(第三个参数):要使用的擦除效果的名称(需要插件支持).默认jQuery提供"linear" 和 "swing".

我们在对元素设置动画的缓动效果,实际就是策略模式的一种实现。这样的缓动算法跟我们使用Jquery的人来说没有直接关系,假如我的项目中某个动 画需要一种新的算法效果,那么我们再去开发一个插件就好了。反之,如果Jquery没有提供这样一种插件机制,那针对需求变化难不成要去改动Jquery 的源码吗?

在《大话设计模式》一书中,作者举例的是一个商场的收银系统,在实际操作中,商場可能因为“双11买一送一”、“满500立减50”、“中秋节全场 11折”等活动而对最终的收费产生变化。如果哪一天商场突然倒闭,全场两元,这时候我们仅需要给软件系统增加一个所有商品价格变两元的插件算法(类)即 可。

我先来模拟一下策略模式的基本代码形态:

            Document                function ConcreteStrategyA(){             this.AlgorithmInterface = function(){                 console.log("算法A");             }         }          function ConcreteStrategyB(){             this.AlgorithmInterface = function(){                 console.log("算法B");             }         }          function ConcreteStrategyC(){             this.AlgorithmInterface = function(){                 console.log("算法C");             }         }          //Context,用一个createStrategy来配置,维护一个对Strategy对象的引用          function Context(strategy){             this.strategy = strategy;             this.ContextInterface = function(){                 strategy.AlgorithmInterface();             }          }          //应用         var context1 = new Context(new ConcreteStrategyA());         context1.ContextInterface();          var context2 = new Context(new ConcreteStrategyB());         context2.ContextInterface();          var context3 = new Context(new ConcreteStrategyC());         context3.ContextInterface();       

通常来说,具体的某一种算法必须保证实现了某一些接口或者继承某个抽象类,才不会发生类型错误,在javascript中去实现接口、抽象类、继承等特性要费一些周章,所以我这个例子是不严谨的,仅从最简单的实现方式着手。

具体实现一个商场收银系统:包括一个单独js文件,和一个具体的实现html文件

//因为要用到数值验证,所以...这里用的是jquery2.1里面的isNum function isNum(obj){     return obj - parseFloat(obj)>=0; } //算法A,没有活动,正常收费 function ConcreteStrategyA(){     this.AlgorithmInterface = function(money){         return money;     } } //算法B,满300减100 function ConcreteStrategyB(MoneyCondition,MoneyReturn){     this.MoneyCondition = MoneyCondition,     this.MoneyReturn    = MoneyReturn;      this.AlgorithmInterface = function(money){         var result=money;         if(money>=MoneyCondition){             result = money - Math.floor(money/MoneyCondition)*MoneyReturn;         }         return result;     } } //算法C,打折 function ConcreteStrategyC(moneyRebate){     this.moneyRebate = moneyRebate;     this.AlgorithmInterface = function(money){         return money*this.moneyRebate;     } }  //Context,用一个createStrategy来配置,维护一个对Strategy对象的引用 //这里将算法相关的从客户端剥离出来,简单工厂模式 function Context(type){     this.strategy = null;     switch(type){         case "a":             this.strategy = new ConcreteStrategyA();             break;         case "b":             this.strategy = new ConcreteStrategyB("300","100");             break;         case "c":             this.strategy = new ConcreteStrategyC("0.8");             break;     }      this.ContextInterface = function(money){         if(!isNum(money)){             money = 0;         }         return this.strategy.AlgorithmInterface(money);     }  }

HTML部分:

            Document              .block {             padding:5px 0;             border-bottom:1px solid #ccc;         }         .menu {margin:10px auto;text-align: center;}                          
                   
     
              
                   var tPrice = document.getElementsByClassName("tPrice"),             tNum   = document.getElementsByClassName("tNum"),             tAlg   = document.getElementsByClassName("tAlg"),             tMoney = document.getElementsByClassName("tMoney"),             total  = document.querySelector("#total");          var addBtn = document.querySelector("#addBtn");         addBtn.addEventListener("click",function(){             var html = '';             var div = document.createElement("div");             div.className="block";             div.innerHTML = html;             this.parentNode.parentNode.insertBefore(div,this.parentNode);         })                   function calculate(e){              //根据事件对象判断事件源,获取同类元素中的位置             var num = 0,className = e.target.className;             switch(className){                 case "tPrice":                     for(var i=tPrice.length-1;i>=0;i--){                         if(tPrice[i]==e.target){                             num = i;                         }                     }                     break;                 case "tNum":                     for(var i=tNum.length-1;i>=0;i--){                         if(tNum[i]==e.target){                             num = i;                         }                     }                     break;                 case "tAlg":                     for(var i=tAlg.length-1;i>=0;i--){                         if(tAlg[i]==e.target){                             num = i;                         }                     }                     break;                 default:                     return;             }               var context = new Context(tAlg[num].value);             var money   = 0;             var totalValue = 0;              money = context.ContextInterface(tPrice[num].value*tNum[num].value);              tMoney[num].value = money;              for(var index=0,len=tMoney.length;index  

最开始我对商品单价、数量、计算方式仅提供一个可操作的地方,这也是《大话设计模式》一书中产品的基本形态,考虑到更良好交互性,我增加了一个按 钮,可以增加更多行。这带来的一点小问题就是:起初我只需要为几个元素绑定事件即可,现在要对可能产生的更多元素绑定事件,所以我就选择了“事件代理”, 获得发生事件的元素位置,改变同一行中的相应元素的值,对于总价,则总是遍历所有的单行总价相加。

BTW,在获取元素的时候使用了getElementsByClassName而没有使用querySelectorAll,是因为后者获取的不是一个动态集合。

接着我尝试将昨天学习的观察者设计模式与策略模式混合起来,起初我是这样做的....

            Document              .block {             padding:5px 0;             border-bottom:1px solid #ccc;         }         .menu {margin:10px auto;text-align: center;}                          
                        
              
                    //发布者         function Publisher(obj){             this.observers = [];             var number = 0;              this.getState=function(){                 return number;             }             this.setState = function(num){                 number = num;                 this.notice();             }         }         Publisher.prototype.addOb=function(observer){             var flag = false;             for (var i = this.observers.length - 1; i >= 0; i--) {                 if(this.observers[i]===observer){                     flag=true;                               }             };             if(!flag){                 this.observers.push(observer);             }             return this;         }          Publisher.prototype.removeOb=function(observer){             var observers = this.observers;             for (var i = 0; i < observers.length; i++) {                 if(observers[i]===observer){                     observers.splice(i,1);                 }             };             return this;         }         Publisher.prototype.notice=function(){             var observers = this.observers;             for (var i = 0; i < observers.length; i++) {                     observers[i].update(this.getState());             };         }          //订阅者         function Subscribe(obj){             this.obj = obj;             this.update = function(data){                 this.obj.value = data;             };         }          //实际应用         var tPrice = document.getElementsByClassName("tPrice"),             tNum   = document.getElementsByClassName("tNum"),             tAlg   = document.getElementsByClassName("tAlg");          var pba = new Publisher(document);          var oba = new Subscribe(document.getElementsByClassName("tMoney"));         var obb = new Subscribe(document.querySelector("#total"));           pba.addOb(oba).addOb(obb);          oba.update = function(num){             var context = new Context(tAlg[num].value);             var money   = 0;              money = context.ContextInterface(tPrice[num].value*tNum[num].value);              this.obj[num].value = money;         }         obb.update = function(num){             var totalValue = 0,                 tMoney = document.getElementsByClassName("tMoney");             for(var index=0,len=tMoney.length;index';             var div = document.createElement("div");             div.className="block";             div.innerHTML = html;             this.parentNode.parentNode.insertBefore(div,this.parentNode);         })                   function calculate(e){               //根据事件对象判断事件源,获取同类元素中的位置             var num = 0,className = e.target.className;             switch(className){                 case "tPrice":                     for(var i=tPrice.length-1;i>=0;i--){                         if(tPrice[i]==e.target){                             num = i;                         }                     }                     break;                 case "tNum":                     for(var i=tNum.length-1;i>=0;i--){                         if(tNum[i]==e.target){                             num = i;                         }                     }                     break;                 case "tAlg":                     for(var i=tAlg.length-1;i>=0;i--){                         if(tAlg[i]==e.target){                             num = i;                         }                     }                     break;                 default:                     return;             }             pba.setState(num);         }          document.addEventListener('keyup',calculate,false);         document.addEventListener('change',calculate,false);       

我在之前学习观察者模式的时候,仅仅是对DOM元素进行了发布者与订阅者的区分,却不知道也没有思考过数据、视图与控制器这种结构中的发布者与订阅 者区分,所以还是要多看看不同的案例。学习完这篇文章以后,我依葫芦画瓢对我这个“收银系统”也弄一下,但是我毕竟还没有学“组合模式”,所以我也不打算 再写一个Controller,仅仅是Model和View之间加入观察者模式。***的结果是这样的:

            Document              .block {             padding:5px 0;             border-bottom:1px solid #ccc;         }         .menu {margin:10px auto;text-align: center;}                                                  
              
                    //实现了观察者的Event类         function Event(pub){             this._pub = pub;             this._listener = [];         }         Event.prototype = {             attach: function(listener){                 this._listener.push(listener);             },             notify: function(num){                 for(var i=0;i=0;i--){                     if(elements[i]===target){                         a = i;                     }                 }                 switch(className){                     case "tPrice":                         b = 0;                         break;                     case "tNum":                         b = 1;                         break;                     case "tMoney":                         b = 3;                         break;                 }                 if(!isNum(a)){                     a = 0;                 }                 if(!isNum(b)){                     b = 0;                 }                 that._model.itemChange([a,b],target.value);             });             this._ele.eTarget.addEventListener('change',function(e){                 var target = e.target,                     className = target.className;                 if(target.nodeName.toLowerCase()!=="select"){                     return;                 }                 var elements = document.getElementsByClassName(className),                     a;                 for(var i=elements.length-1;i>=0;i--){                     if(elements[i]===target){                         a = i;                     }                 }                 that._model.itemChange([a,2],target.value);             });             this._ele.addBtn.addEventListener('click',function(){                 var html = '';                 var div = document.createElement("div");                 div.className="block";                 div.innerHTML = html;                 this.parentNode.parentNode.insertBefore(div,this.parentNode);                  that._model.itemAdd([0,0,"a",0]);             });         }         View.prototype.getTotal= function(pub,num){             var price = this._model._data[num][0],                 number = this._model._data[num][1],                 alg = this._model._data[num][2],                 money = this._model._data[num][3];              var context = new Context(alg);             money = context.ContextInterface(price*number);             this._model._data[num][3]=money;              var total = 0;             for(var i=0;i  

在形成上面的最终结果途中,在对数据进行计算并且将结果传递给Model时,我用了会触发观察者模式更新内容的函数,从而导致在一次计算以后又更新 又计算又更新的***循环中,改为直接对Model中的数据进行操作就没事了。

到此,关于“JavaScript策略模式如何实现”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注创新互联网站,小编会继续努力为大家带来更多实用的文章!


分享标题:JavaScript策略模式如何实现
网页路径:http://cdkjz.cn/article/jooigc.html
多年建站经验

多一份参考,总有益处

联系快上网,免费获得专属《策划方案》及报价

咨询相关问题或预约面谈,可以通过以下方式与我们联系

大客户专线   成都:13518219792   座机:028-86922220