摘要:而且,說完起立之后,副班長也不知道誰會(huì)說老濕好。不要緊,我們可以使用命令模式來彌補(bǔ)這個(gè)缺陷,因?yàn)槊钅J阶畲蟮囊粋€(gè)擴(kuò)展性就是命令者和命令的執(zhí)行者分開了。這樣可以清楚的說明命令模式的優(yōu)勢到底在哪里。
命令模式
望文生義,所謂的命令模式其實(shí)就是:
發(fā)出一定的指令,然后由對象接受并且執(zhí)行
需要強(qiáng)調(diào)一點(diǎn),就是對于命令的發(fā)出者來說,他并不知道該命令是給誰,執(zhí)行效果是怎樣,他只管發(fā)出命令就行。聽到這里感覺和發(fā)布訂閱者模式有異曲同工的效果。 但事實(shí)上,他們兩者應(yīng)用的場景還是有比較大的區(qū)分。不僅寫法上有不同,而且執(zhí)行的過程也有所不同。要知道在命令模式里面執(zhí)行的效果是1對1,而在訂閱者模式里面是1對>=1的.
你在逼逼什么?
哦,說明白一點(diǎn)。 就和上課一樣。 老師進(jìn)教室了,首先說:“上課!”. 接著,你們的monitor 會(huì)立馬接上: "起立!"。 然后,你們就會(huì)異口同聲的說:"老濕好~"。 沒錯(cuò),分析一下。 當(dāng)老師說上課的時(shí)候,他并不會(huì)知道誰會(huì)說起立,比如今天班長談戀愛去了,那副班長頂上。 而且,說完起立之后,副班長也不知道誰會(huì)說老濕好。 也就是命令的發(fā)出者,只管發(fā)出一個(gè)命令,然后你們只管執(zhí)行就over了.
talk is cheap, show u code.
//事件發(fā)出者 var setCommand = function(ele,command){ //命令的綁定者 ele.onclick = function(){ command.do(); } } //事件的執(zhí)行者 var location = (function() { //執(zhí)行事件類 var ball = getEle("#ball"); var move = function(direct) { return function() { var style = ball.style, dir = parseInt(style[direct]); style[direct] = `${dir-200}px`; } } var moveUp = move("top"); var moveDown = move("down"); var moveLeft = move("left"); var moveRight = move("right"); return { moveUp, moveDown, moveLeft, moveRight } })(); //封裝命令 var MoveUp = function(exer){ this.exer = exer; } MoveUp.prototype.do = function(){ this.exer.moveUP(); } var MoveDown = function(exer){ this.exer = exer; } MoveDown.prototype.do = function(){ this.exer.moveDown(); } var MoveLeft = function(exer){ this.exer = exer; } MoveLeft.prototype.do = function(){ this.exer.moveLeft(); } var MoveRight = function(exer){ this.exer = exer; } MoveRight.prototype.do = function(){ this.exer.moveRight(); } setCommand(getEle("upBtn"), new MoveUp(location)); //給向上的button,綁定向上的執(zhí)行程序 setCommand(getEle("downBtn"), new MoveDown(location)); //... setCommand(getEle("leftBtn"), new MoveLeft(location)); //... setCommand(getEle("rightBtn"), new MoveRight(location)); //....
可以清晰的看到,在命令模式中,觸發(fā)事件(onclick)和執(zhí)行程序(command.do())都是已知的。 但是這個(gè)執(zhí)行的消息給誰,或者執(zhí)行產(chǎn)生的效果是怎樣的,在命令的發(fā)出者這一方都是未知的。需要注意的是,這時(shí)候的未知只限于命令的發(fā)出者而言。也就是現(xiàn)在命令模式將發(fā)出者和執(zhí)行者給解耦開,即,可變的部分和不可變的部分分開。
上面逼逼這么多到底在說shenme...
其實(shí)一切原理都是枯燥的,實(shí)例才是王道。 來,我們來做個(gè)比較。也就是不使用命令模式,直接寫上面的例子(偷個(gè)懶,只寫moveUP部分).
var ele = getEle("#ball"); getELe(".moveUp").onclick = function(){ var style = this.style, dir = parseInt(style["top"]); style["top"] = `${dir-200}px`; } }
上面的代碼同樣能完成上面辣么辣么長的代碼完成的效果,那為什么還要使用上面的寫法呢?
艸~ 請問,你下面那段代碼,能體現(xiàn)你的bigger嗎? 能體現(xiàn)你是代碼藝術(shù)家的feeling嗎?能體現(xiàn)你的思維能力嗎?
No NO No~
我們來分析下why.
首先下面那段代碼可以完成上面的功能,但是萬一有一天,一個(gè)名叫產(chǎn)經(jīng)的生物和你說
"親愛的,你能不能在加一個(gè)button,讓這個(gè)球可以斜著走,可以轉(zhuǎn)個(gè)圈呢? 哈哈,我相信你一定可以的。"
呵呵,你話都沒說。 想當(dāng)然這個(gè)鍋,你必須背。好吧,那開始做吧。(用那個(gè)渣渣代碼演示一遍).
function getY(x){ var k = 1.2; return k*x; } getELe("#diagnoal").onclick = function(){ var style = ele.style, x = parseInt(style["left"]), y = parseInt(style["top"]), style["left"] = `${x-200}px`; style["top"] = `${y-getY(200)}px`; } }
可以想象,最后如果產(chǎn)經(jīng)的需求不斷增多,那么你在事件處理的回調(diào)會(huì)越來越復(fù)雜,比如:
"親愛的,你斜著走都實(shí)現(xiàn)了,那4個(gè)方向能不能都可以走呢?"
我想這時(shí)候,你應(yīng)該會(huì)懵逼了。不要緊,我們可以使用命令模式來彌補(bǔ)這個(gè)缺陷,因?yàn)槊钅J阶畲蟮囊粋€(gè)擴(kuò)展性就是命令者和命令的執(zhí)行者分開了。而且在上面面向過程的代碼中,看不出什么邏輯出來,只是知道,這個(gè)click是觸發(fā)什么的。 而事件回調(diào)中的代碼重用性也是非常低的。
這里使用命令模式重構(gòu)一遍
//其他的還是一樣,這里主要將4個(gè)方向的代碼重構(gòu)一下
var location = (function() { //執(zhí)行事件類 var ball = getEle("#ball"); var compMove = function(hori,vert) { //垂直和水平方向 var k = 1.2; //移動(dòng)的斜率 var getY = function() { return k * x; } return function() { var style = ball.style, x = parseInt(style[hori]), //水平方向上的位置 y = parseInt(style[vert]); //垂直方向上的位置 style[hori] = `${x-200}px`; style[vert] = `${y-getY(200)}px`; //執(zhí)行移動(dòng) } }; //斜方向綁定代碼 var moveLU = compMOve("left","top"); var moveRU = compMOve("right","top"); var moveLB = compMOve("left","bottom"); var moveRB = compMOve("right","bottom"); return { moveLU moveRU, moveLB, moveRB } })(); //封裝命令 var MoveLU = function(exer) { this.exer = exer; } MoveLU.prototype.do = function() { this.exer.moveLU(); } setCommand(getEle("leftUpBtn"), new MoveLU(location)); //給向上的button,綁定向上的執(zhí)行程序
可以看出來,雖然代碼多,但是至少我們將改動(dòng)的地方降到最低了。
setCommand這個(gè)不變,變的只是綁定click的對象和執(zhí)行者。 這樣可以清楚的說明命令模式的優(yōu)勢到底在哪里。
當(dāng)然,我們還可以做一個(gè)優(yōu)化,要知道,js是一門函數(shù)至上的語言,因?yàn)楹瘮?shù)可以像參數(shù)一樣被傳來傳去,所以可以這樣改寫命令的綁定者.
var setCommand = function(ele,fn){ ele.onclick = function(){ fn(); } } setCommand(getEle("leftUpBtn",()=>{location.moveLU()}))); //給向上的button,綁定向上的執(zhí)行程序
這樣就可以省去中間一大堆的事件修飾,從而將函數(shù)直接暴露使用。推薦這樣寫法,因?yàn)檫@個(gè)才是js的真正實(shí)力。
要知道一個(gè)模式的精華不是看他能怎么用,而是要看你怎么用他。
其實(shí),緩存并不是什么高上大的東西,就是在函數(shù)里名,有一個(gè)變量來保存你的結(jié)果,而你可以遍歷這個(gè)結(jié)果.
function fb(num) { if (num <= 1) { return 1; } return num * fb(--num) } //緩存代理出場了 var cProxy = (function() { var cache = {}; return function(num) { if (cache[num]) { console.log(`this is cache ${cache[num]}`); return cache[num]; } return cache[num] = fb(num); } })(); //測試 console.log(cProxy(4)); //24 cProxy(4); //"this is cache 24"
上面是我以前寫代理緩存的例子。 里面有個(gè)叫cache的東西,就是來保存你的結(jié)果(放在內(nèi)存中),以備下次使用。
而命令模式的緩存有個(gè)極大的用途就是一個(gè) 撤銷和重做的效果.
在上面的例子中可以保留每一個(gè)節(jié)點(diǎn)小球的位置(簡單起見,還是以最初的上下左右為基準(zhǔn)吧)
由于代碼過長,我放在fiddle里面(里面代碼可能會(huì)和上面有很大出入,但是如果理解了上面的說法的話,我相信理解起來肯定很快的)。有興趣可以看看。是個(gè)實(shí)例demo哦。 :)
撤銷實(shí)例
特此說明,由于使用原生寫的里面會(huì)有寫hacks,如果大家有自己獨(dú)到的見解,歡迎拍磚(請輕點(diǎn)~). 也歡迎點(diǎn)個(gè)推薦唄。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/78506.html
摘要:今天就先給大家講大數(shù)據(jù)分析工程師。所以你要和我說你在外面培訓(xùn)了個(gè)月的大數(shù)據(jù)分析后,就想做了,那請你再考慮考慮。而他們鼓吹的大數(shù)據(jù)分析師,其實(shí)就是。 showImg(https://segmentfault.com/img/remote/1460000018722710?w=1000&h=750); Overview: 序 基本概念 DS的職能要求 DE的職能要求 總結(jié) 一、序 今天...
摘要:經(jīng)驗(yàn)少的程序員小猿同學(xué)畢業(yè)工作一年了,在公司感覺自己的能力很好了,能力大于老板給的價(jià)值了,所以想要漲工資,但是老板給漲的不夠理想,小猿聽說跳槽可以讓自己的工資翻倍,毅然決然的就辭職了,決定重新找工作。 又到了一周一次的周末心靈雞湯的時(shí)間了,希望大家能夠痛痛快快的喝了這碗雞湯,讓這酸爽的感覺使你永生難忘。哈哈……這周又有幾個(gè)人,尤其是畢業(yè)生在「非著名程序員」微信公眾號(hào)里私聊我關(guān)于找不到工...
摘要:我自己總結(jié)的學(xué)習(xí)的系統(tǒng)知識(shí)點(diǎn)以及面試問題,已經(jīng)開源,目前已經(jīng)。面試官那你都了解里面的哪些東西呢我哈哈哈這可是我的強(qiáng)項(xiàng),從,說到,,又說到線程池,分別說了底層實(shí)現(xiàn)和項(xiàng)目中的應(yīng)用。 我自己總結(jié)的Java學(xué)習(xí)的系統(tǒng)知識(shí)點(diǎn)以及面試問題,已經(jīng)開源,目前已經(jīng) 35k+ Star。會(huì)一直完善下去,歡迎建議和指導(dǎo),同時(shí)也歡迎Star: https://github.com/Snailclimb... ...
閱讀 1211·2021-11-23 09:51
閱讀 1990·2021-10-08 10:05
閱讀 2348·2019-08-30 15:56
閱讀 1908·2019-08-30 15:55
閱讀 2643·2019-08-30 15:55
閱讀 2497·2019-08-30 13:53
閱讀 3508·2019-08-30 12:52
閱讀 1256·2019-08-29 10:57