javascript設(shè)計(jì)模式之策略模式
一. 認(rèn)識(shí)策略模式
策略模式的定義:定義一系列的算法,將他們一個(gè)個(gè)封裝起來(lái),使他們直接可以相互替換。
策略模式是開(kāi)發(fā)中常用的第二種設(shè)計(jì)模式,它在開(kāi)發(fā)中非常常見(jiàn),由兩部分組成。第一部分是策略類,封裝了許多具體的,相似的算法。第二部分是環(huán)境類,接受客戶請(qǐng)求,隨后將請(qǐng)求委托給策略類。說(shuō)的通俗一點(diǎn)就是將相同算法的函數(shù)存放在一個(gè)包裝里邊,每個(gè)函數(shù)用相同的方式拿出來(lái),就叫做策略模式。下面我們來(lái)通過(guò)代碼實(shí)現(xiàn)深入了解一下。
二. 具體實(shí)現(xiàn)和思想
假如需要實(shí)現(xiàn)一個(gè)計(jì)算員工獎(jiǎng)金的程序,效績(jī)?yōu)?S 則發(fā)基本工資的4倍,A 則3倍,以此類推,那么我們正常實(shí)現(xiàn)該代碼,是通過(guò)判斷分支語(yǔ)句來(lái)實(shí)現(xiàn)。
1. 通過(guò)分支實(shí)現(xiàn)
let bonus = function (performance, salary) { if(performance === "S") { return salary*4; } if(performance === "A") { return salary*3; } if(performance === "B") { return salary*2; } }
分析:該實(shí)現(xiàn)存在顯著的缺點(diǎn),如果隨著效績(jī) 的擴(kuò)展,比如增加C,D,E, if 分支不斷累加,使得代碼越來(lái)越龐大。
因此我們使用策略模式來(lái)重構(gòu)代碼。
2.使用策略模式實(shí)現(xiàn)
let performanceS = function () {}; performanceS.prototype.calculate = function ( salary ) { return salary*4 } let performanceA = function () {}; performanceA.prototype.calculate = function ( salary ) { return salary*3 } let performanceB = function () {}; performanceB.prototype.calculate = function ( salary ) { return salary*2 } let performanceC = function () {}; performanceC.prototype.calculate = function ( salary ) { return salary*1 } let Bonus = function () { this.salary = null; // 原始工資 this.strategy = null; // 原始績(jī)效 } Bonus.prototype.setSalary = function ( salary ) { this.salary = salary; } Bonus.prototype.setStrategy = function ( strategy ) { this.strategy = strategy; } Bonus.prototype.getBonus = function () { if(!this.strategy) { throw new Error("未設(shè)置績(jī)效"); } return this.strategy.calculate(this.salary); } let bonus = new Bonus(); bonus.setSalary(10000); bonus.setStrategy(new performanceS()); console.log(bonus.getBonus());
分析:重構(gòu)后,我們將每種績(jī)效算法單獨(dú)成一個(gè)函數(shù),需要計(jì)算某種績(jī)效時(shí)只需要將其傳入 getBonus 函數(shù)中,去掉了 if 分支,減少了性能消耗,并且使代碼有了彈性,隨時(shí)增加其他績(jī)效,不需要更改原代碼。
主要思想:這段代碼基于面向?qū)ο笳Z(yǔ)言,引入了多態(tài)的概念,不適用于js。
3. JavaScript 版本的策略模式
// js中函數(shù)也是對(duì)象,直接將 strategy 定義為函數(shù) let strategy = { "S": function ( salary ){ return salary*4; }, "A": function ( salary ) { return salary*3; }, "B": function ( salary ) { return salary*2; } } let calculateBonus = function ( level, salary ) { return strategy[ level ]( salary ); } console.log(calculateBonus('A', 20000)) // 6000
分析:js 的對(duì)象可以直接創(chuàng)建,將函數(shù)封裝進(jìn)去,這樣一來(lái),代碼顯得清晰簡(jiǎn)潔。代碼的復(fù)用,彈性也隨之變強(qiáng)。
以上就是 js 設(shè)計(jì)模式策略模式的主要思想和實(shí)現(xiàn),他在應(yīng)用中有兩個(gè)主要的作用,一是策略模式實(shí)現(xiàn)晃動(dòng)動(dòng)畫(huà);二是實(shí)現(xiàn)表單驗(yàn)證,有能力有興趣的小伙伴可以往下看。
三. 策略模式的實(shí)際運(yùn)用
1. 使用策略模式實(shí)現(xiàn)緩存動(dòng)畫(huà)
// 緩動(dòng)算法 let tween = { linear (t, b, c, d) { return c*t/d + b; }, easeIn (t, b, c, d) { return c*(t /= d) *t + b; }, strongEaseIn (t, b, c, d) { return c*(t /= d) *t *t *t *t + b; } } // 定義一個(gè)動(dòng)畫(huà)類,參數(shù)為要運(yùn)動(dòng)的 dom 節(jié)點(diǎn) let Animate = function ( dom ) { this.dom = dom; this.startTime = 0; this.startPos = 0; this.endPos = 0; this.propertyName = null; this.easing = null; // 緩動(dòng)算法 this.duration = null; } // 啟動(dòng)方法 Animate.prototype.start = function (propertyName, endPos, duration, easing) { this.startTime =+ new Date; this.startPos = this.dom.getBoundingClientRect()[propertyName]; // dom 初始位置 this.propertyName = propertyName; this.endPos = endPos; this.duration = duration; this.easing = tween[easing]; let self = this; let timeId = setInterval(() => { if( self.step() === false){ clearInterval(timeId); } }, 19); } // 實(shí)現(xiàn)小球每一幀要做的事情 Animate.prototype.step = function () { let t =+ new Date; if(t>this.startTime + this.duration){ this.update(this.endPos); return false; } let pos = this.easing(t - this.startTime, this.startPos, this.endPos - this.startPos, this.duration); this.update(pos); } Animate.prototype.update = function (pos) { this.dom.style[this.propertyName] = pos + 'px'; } let test = function () { let div = document.getElementById('div'); let animate = new Animate(div); animate.start('left', 500, 1000, 'strongEaseIn'); // animate.start('top', 1500, 500, 'strongEaseIn'); } test();
2. 使用策略模式進(jìn)行表單驗(yàn)證
let strategies = { isNonEmpty ( value, errorMsg) { // 判斷是否為空 if(value === '') { return errorMsg; } }, minLength (value, length, errorMsg){ if (value.length < length) { return errorMsg; } } } let dom = document.forms[0].acount; let validatarFunc = function () { let validator = new Validator(); // 添加校驗(yàn)規(guī)則 validator.add(dom, 'isNonEmpty', '用戶名不能為空!'); let errorMsg = validator.start(); return errorMsg; // 返回校驗(yàn)結(jié)果 } // 實(shí)現(xiàn)表單校驗(yàn)保存類 let Validator = function () { this.cache = []; // 保存校驗(yàn)規(guī)則 } Validator.prototype.add = function (dom, rule, errorMsg) { let ary = rule.split(':'); this.cache.push( function(){ let strategy = ary.shift(); ary.unshift(dom.value); ary.push( errorMsg ); return strategies[strategy].apply(dom, ary); }) } Validator.prototype.start = function () { for(let i = 0, validatorFunc; validatorFunc = this.cache[i++];){ let msg = validatorFunc(); if( msg ) { return msg; } } } document.forms[0].addEventListener('submit', (e) =>{ let errorMsg = validatarFunc(); if(errorMsg){ alert(errorMsg); e.preventDefault(); } })
分析:第一個(gè)實(shí)現(xiàn)中是把緩動(dòng)算法封裝在一個(gè)對(duì)象中,調(diào)用他們時(shí)便于相互替換,也便于擴(kuò)展。
第二個(gè)實(shí)現(xiàn)是將校驗(yàn)規(guī)則封裝起來(lái)。
四. 總結(jié)
策略模式利用組合、委托、多態(tài)等技術(shù)思想,有效避免多重條件選擇語(yǔ)句,將算法封裝在 strategy 中,使他們易于切換、擴(kuò)展。
本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
詳解JavaScript實(shí)現(xiàn)異步Ajax
本文詳細(xì)講解了JavaScript實(shí)現(xiàn)異步Ajax的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-05-05JavaScript預(yù)編譯和執(zhí)行過(guò)程詳解
本文詳細(xì)講解了JavaScript預(yù)編譯和執(zhí)行過(guò)程,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06實(shí)現(xiàn)高性能JavaScript之執(zhí)行與加載
avaScript在瀏覽器中的性能,此問(wèn)題因JavaScript的阻塞特征而復(fù)雜,也就是說(shuō)JavaScript運(yùn)行時(shí)其他的事情不能被瀏覽器處理,事實(shí)上,大多數(shù)瀏覽器使用單進(jìn)程處理JavaScript運(yùn)行等多個(gè)任務(wù),而同一時(shí)間只能有一個(gè)任務(wù)被執(zhí)行。2016-01-01淺談關(guān)于JavaScript API設(shè)計(jì)的一些建議和準(zhǔn)則
這篇文章主要介紹了淺談關(guān)于JavaScript API設(shè)計(jì)的一些建議和準(zhǔn)則,文中列舉了許多知名的JS API進(jìn)行輔助說(shuō)明,極力推薦!需要的朋友可以參考下2015-06-06JavaScript簡(jiǎn)介_(kāi)動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
JavaScript是一種基于對(duì)象(Object)和事件驅(qū)動(dòng)(EventDriven)并具有安全性能的腳本語(yǔ)言,javascript的出現(xiàn)使得網(wǎng)頁(yè)和用戶之間實(shí)現(xiàn)了一種實(shí)時(shí)性的,動(dòng)態(tài)性的,交互性的關(guān)系,使網(wǎng)頁(yè)包含更多活躍的元素和更加精彩的內(nèi)容2017-06-06JavaScript中window、doucment、body的解釋
JavaScript中window、doucment、body是什么意思呢,下面為大家做個(gè)介紹,不知道的朋友可以參考下2013-08-08Javascript入門學(xué)習(xí)第六篇 js DOM編程
上篇文章納悶的問(wèn)題,將在這章和以后的幾章里,慢慢搞定。 從今天起,開(kāi)始學(xué)習(xí)DOM編程 讓我們慢慢稱為一名初級(jí)的js程序員。 然后往js匠人方向發(fā)展。2008-07-07JavaScript學(xué)習(xí)筆記整理_用于模式匹配的String方法
下面小編就為大家?guī)?lái)一篇JavaScript學(xué)習(xí)筆記整理_用于模式匹配的String方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-09-09