Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
造函數(shù)模式
在JavaScript里,構(gòu)造函數(shù)通常是認(rèn)為用來實現(xiàn)實例的特殊的構(gòu)造函數(shù)。通過new關(guān)鍵字來調(diào)用定義的構(gòu)造函數(shù),你可以告訴JavaScript你要創(chuàng)建一個新對象并且新對象的成員聲明都是構(gòu)造函數(shù)里定義的。在構(gòu)造函數(shù)內(nèi)部,this關(guān)鍵字引用的是新創(chuàng)建的對象。
作為一個老聯(lián)盟fans,一定要親手實現(xiàn)一下設(shè)計模式也可以融會貫通。
現(xiàn)在打算創(chuàng)建一個英雄聯(lián)盟對象,需要地圖,英雄,士兵,野怪,還有開始游戲的按鈕。
function LOL(maps, heros, soldier, monster) {
this.maps=maps
this.heros=heros
this.soldier=soldier
this.monster=monster
this.start=function() {
return '地圖:' + this.maps + '\n對戰(zhàn)英雄:' + this.heros.join() + '\n小兵類型:' + this.soldier + '\n野怪:' + this.monster + '\n'
}
}
var game1=new LOL('召喚師峽谷', ['影流之主', '詭術(shù)妖姬'], '超級兵', '紅buff')
var game2=new LOL('大亂斗', ['影流之主', '詭術(shù)妖姬'], '超級兵', '紅buff')
console.log(game1.start())
console.log(game2.start())
這樣寫代碼,每局游戲需要重新創(chuàng)建一個英雄聯(lián)盟實例,
這樣使用構(gòu)造器,有多少個game就需要多少個start函數(shù)方法,如果共用一個start方法,可以節(jié)約很多內(nèi)存
function LOL(maps, heros, soldier, monster) {
this.maps=maps
this.heros=heros
this.soldier=soldier
this.monster=monster
}
LOL.prototype.start=function() {
return '地圖:' + this.maps + '\n對戰(zhàn)英雄:' + this.heros.join() + '\n小兵類型:' + this.soldier + '\n野怪:' + this.monster + '\n'
}
var game1=new LOL('召喚師峽谷', ['影流之主', '詭術(shù)妖姬'], '超級兵', '紅buff')
var game2=new LOL('大亂斗', ['影流之主', '詭術(shù)妖姬'], '超級兵', '紅buff')
console.log(game1.start())
console.log(game2.start())
如果讓start方法變成大家通用的就好了,因此把LOL.prototype.start改寫,這樣所以的LOL實例就可以共用一個方法,從原型鏈上繼承即可
上面的方式可以節(jié)省內(nèi)存,start實例函數(shù)可以在所有LOL對象的實例中使用
如果不使用new 也可以有其他方式創(chuàng)建對象
function LOL(maps, heros, soldier, monster) {
this.maps=maps
this.heros=heros
this.soldier=soldier
this.monster=monster
this.start=function() {
return '地圖:' + this.maps + '\n對戰(zhàn)英雄:' + this.heros.join() + '\n小兵類型:' + this.soldier + '\n野怪:' + this.monster + '\n'
}
}
var game3=new Object();
LOL.call(game3, "扭曲叢林", ['影流之主', '劍圣'], '遠(yuǎn)程兵', '大龍');
console.log(game3.start())
//也可以不使用new ,通過call方法在game3的作用域調(diào)用LOL
這種方式雖然可以創(chuàng)建新的構(gòu)造函數(shù),但卻不能繼承LOL原型上的函數(shù)
如果直接運行LOL()函數(shù)(不使用new的情況下),由于this指向的是window對象,因此start方法會變成window.start()
如果強制要求函數(shù)使用new 方法也可以如下創(chuàng)建:
function LOL(maps, heros, soldier, monster) {
if (!(this instanceof LOL)) {
return new LOL(maps, heros, soldier, monster);
}
this.maps=maps
this.heros=heros
this.soldier=soldier
this.monster=monster
}
通過判斷this的instanceof,就可以知道究竟是來自new方法,還是說是直接調(diào)用。如果是直接調(diào)用的話,判斷條件為true,還是會return一個新的實例。
e.g:
var s=new String("lol");
var n=new Number(101);
var b=new Boolean(true);
// s n b返回的是實例對象
//String{
// 0: 'l',
// 1: 'o',
// 2: 'l'
// }
//可以直接給變量賦值,或者不加new 關(guān)鍵詞
外觀模式最大的體現(xiàn)其實就是入口,比如init()函數(shù),把一些內(nèi)部的函數(shù)都放在這個門面之下,只需要調(diào)用這個門面函數(shù),其他亂七八糟的功能都可以實現(xiàn)。
現(xiàn)在有一個英雄,叫做亞索,我希望給他一些配置,比如技能,衣服等
function YaSuo() {
}
function Qskill (hero) {
hero.prototype.Qskill=function() {
console.log('hasaki!!')
}
}
function Wskill (hero) {
hero.prototype.Wskill=function() {
console.log('風(fēng)墻')
}
}
function Eskill (hero) {
hero.prototype.Eskill=function() {
console.log('快樂')
}
}
function Rskill (hero) {
hero.prototype.Rskill=function() {
console.log('痛里唉該痛')
}
}
function Skin (hero, skin) {
hero.prototype.skin=skin
}
function CreateYasuo () {
Qskill(YaSuo)
Wskill(YaSuo)
Eskill(YaSuo)
Rskill(YaSuo)
Skin(YaSuo, 'originSkin')
return new YaSuo()
}
CreateYasuo()
// 創(chuàng)建成功 外觀模式啟動
通過上面的代碼,成功創(chuàng)建了一個美麗的亞索。我們最后只需要了解,外觀模式不僅簡化類中的接口,而且對接口與調(diào)用者也進(jìn)行了解耦。外觀模式經(jīng)常被認(rèn)為開發(fā)者必備,它可以將一些復(fù)雜操作封裝起來,并創(chuàng)建一個簡單的接口用于調(diào)用。
說白了就是用一個接口封裝其它的接口。
外觀模式優(yōu)點就是易使用。缺點則是,當(dāng)連續(xù)使用外觀模式創(chuàng)建的接口時,可能會產(chǎn)生性能問題。
e.g.
var addMyEvent=function (el, ev, fn) {
if (el.addEventListener) {
el.addEventListener(ev, fn, false);
} else if (el.attachEvent) {
el.attachEvent('on' + ev, fn);
} else {
el['on' + ev]=fn;
}
};
這是最常見對監(jiān)聽事件的處理,前端必會。其中的addMyEvent就是對其他三個接口的封裝,產(chǎn)生了一個門面,也就是外觀模式。
其實代理模式我們生活中接觸的很多了。比如es6中的proxy對象,還有我們平時上網(wǎng)用的VPN。那其實代理模式,就是讓一個對象幫助其他的對象來做事。
比如我現(xiàn)在想創(chuàng)建一個英雄,名字叫做卡莉斯塔,俗稱滑板鞋。這個英雄有個特點,當(dāng)她放R技能的時候,會把一個對象拉過來到自己身邊幾秒,代理這個對象的走路行為,禁止他釋放技能等等,那這就要用到代理模式了。
// 聲明走路動作
function Walk (hero) { // 代理期間執(zhí)行的操作
return function() {console.log(hero + ' is walk')}
}
function Kalisita () { // proxy
this.walk=Walk('Kalisita')
this.Rskill=function(hero) { // 傳入要拉取的英雄
this.walk=function() {
Walk('Kalisita')() // 既需要自己走
hero.walk() // 還需要帶著人一起走
}
}
}
function HeroA () { // 被代理走路的英雄
this.walk=Walk('heroA')
}
var k=new Kalisita()
var a=new HeroA()
k.walk() // Kalisita is walk
a.walk() // heroA is walk
k.Rskill(a) // k把a的walk事件代理了, 現(xiàn)在k觸發(fā)walk的同時,也會帶著a一起walk哦
k.walk()
// Kalisita is walk
// heroA is walk
代理模式主要用于幾點,
詳情可以參考《大話設(shè)計模式》
而我們前端代碼中用的比較多的,應(yīng)該就是vue.js中對data中數(shù)據(jù)響應(yīng)式的代理。vue3中也將使用大量ES6支持的Proxy對象來改寫。
e.g.
通過代理,嘗試設(shè)置私有屬性
function getPrivateProps(obj, filterFunc) {
return new Proxy(obj, {
get(obj, prop) {
if (!filterFunc(prop)) {
let value=Reflect.get(obj, prop);
// 如果是方法, 將this指向修改原對象
if (typeof value==='function') {
value=value.bind(obj);
}
return value;
}
},
set(obj, prop, value) {
if (filterFunc(prop)) {
throw new TypeError(`Cant set property ${prop}`);
}
return Reflect.set(obj, prop, value);
},
has(obj, prop) {
return filterFunc(prop) ? false : Reflect.has(obj, prop);
},
ownKeys(obj) {
return Reflect.ownKeys(obj).filter(prop=> !filterFunc(prop));
},
getOwnPropertyDescriptor(obj, prop) {
return filterFunc(prop) ? undefined : Reflect.getOwnPropertyDescriptor(obj, prop);
}
});
}
function propFilter(prop) {
return prop.indexOf('_')===0;
}
本次分享了三種設(shè)計模式,分別為構(gòu)造函數(shù)模式,外觀模式,代理模式;都是日常開發(fā)很常用的設(shè)計模式。
其中es6proxy可以訪問阮老師博客查看詳細(xì)api,具體使用也可以借鑒vue源碼。代理模式雖然很好用,但也不是任何時候都建議使用,如果你的代碼需要獲得某些對象的權(quán)限,不妨可以使用一下代理模式。在比較簡單的場景,可能就沒有必要了。
外觀模式是最常用的,畢竟每一個js文件總是需要一個入口的。無論是main函數(shù)還是init函數(shù),都是起到一個外觀包裝的作用。當(dāng)然外觀模式并不是必須作為一個文件入口存在,只要能把重復(fù)的代碼提煉出來,就是一個合理的外觀模式。
構(gòu)造函數(shù)模式就不多說了,簡單好用。
復(fù)制代碼是危險的。如果有兩段相同的代碼,幾乎可以說一定是有問題的,因為每次改動,要維護(hù)兩段代碼
盡量減少IO操作,如操作數(shù)據(jù)庫,網(wǎng)絡(luò)發(fā)送,甚至printf ,這些操作比直接操作內(nèi)存,慢很多倍、
修改Bug時,一定要從最簡單的基本的地方開始檢查,不要檢查到最底層沒問題,發(fā)現(xiàn)是傳入的某個參數(shù)是錯的。先不要懷疑系統(tǒng)的部分。
設(shè)計架構(gòu),同時了解細(xì)節(jié),有些Bug,調(diào)起來可能費時費力,甚至花個二三天,其實當(dāng)時寫的時候,只要稍微注意,就可以輕松避免。避免Bug的代價與找出并修改Bug的代價,實在是差太多了。
把一段長代碼,分成很多小函數(shù),便于維護(hù),連自己都不愿看,不愿改的代碼,百分百有問題。
寫程序時,先把流程搞清楚。把各個流程用的函數(shù)寫清楚,函數(shù)可以留空,這樣編程就變成了填空題。
做新功能時,把數(shù)據(jù)結(jié)構(gòu)的設(shè)計,放在較重要的位置
希望這次分享能夠既有趣,又讓你得到收獲,謝謝閱讀。
源自:https://juejin.im/post/5ebe65a0f265da7bd76bb626
聲明:文章著作權(quán)歸作者所有,如有侵權(quán),請聯(lián)系小編刪除。
閩南網(wǎng)]
lol揮別2018起航2019活動正式開啟,不少玩家想知道召喚師圖標(biāo)免費領(lǐng)取方法。
lol揮別2018起航2019活動介紹:
揮別2018起航2019
活動時間:即日起-1月14日
領(lǐng)取截止時間:2019年1月21日15:59
活動入口:點擊進(jìn)入
圖標(biāo)領(lǐng)取地址:https://lol.qq.com/act/a20180929awards/index.html#box2
起航2019召喚師圖標(biāo)寶箱介紹:
1、一般活動結(jié)束后10個工作日內(nèi)可在本頁面領(lǐng)取。
2、請在截止時間前領(lǐng)取道具,逾期作廢。
3、領(lǐng)取之前請先進(jìn)入一次游戲商城才能收到道具。
4、領(lǐng)取之后請重新進(jìn)入游戲查收道具。
關(guān)于lol揮別2018起航2019活動的介紹就到這。
大家好,這是第三篇作者對于設(shè)計模式的分享了,前兩篇可以參考:
手寫一下JavaScript的幾種設(shè)計模式 (工廠模式,單例模式,適配器模式,裝飾者模式,建造者模式)
用英雄聯(lián)盟的方式講解JavaScript設(shè)計模式(一)! (構(gòu)造函數(shù)模式,外觀模式,代理模式)
設(shè)計模式在編程開發(fā)中用途十分廣泛,每一個模式描述了一個在我們周圍不斷重復(fù)發(fā)生的問題,以及解決問題的核心!很多的時候,對于我們其實如何選擇適合的設(shè)計模式,才更加消耗時間。從之前的文章,每一個設(shè)計模式都會有一到兩個例子,既可以給自己以后開發(fā)回憶設(shè)計模式提供幫助,也希望可以給讀者一些啟發(fā)。
策略模式定義了算法家族,分別封裝起來,讓他們之間可以互相替換,此模式讓算法的變化不會影響到使用算法的客戶。
那聽起來云山霧繞,怎么都涉及到 算法 了 ?難道我一個前端是時候進(jìn)攻算法大軍了嗎。其實并不是,用一個超級常見的例子就可以解釋!
讓我們又回到英雄聯(lián)盟,當(dāng)我們第一次登陸英雄聯(lián)盟的時候,需要輸入一個新的姓名吧?起名規(guī)則起碼得有以下這幾條:
其中具體的設(shè)定,只有開發(fā)者才知道了,身為玩家只能注意到這幾點,那策略模式怎么體現(xiàn)在這里的呢?首先我們實現(xiàn)一個顯而易見功能的例子:
var validator={
validate: function (value, type) {
switch (type) {
case 'isNonEmpty ':
{
return true; // 名字不能為空
}
case 'isNoNumber ':
{
return true; // 名字 不是 純數(shù)字
break;
}
case 'isExist ':
{
return true; // 名字已存在
}
case 'isLength':
{
return true; // 長度合理
}
}
}
};
復(fù)制代碼
上述代碼可以實現(xiàn)一個表單驗證系統(tǒng),剛創(chuàng)建角色起名字的時候驗證那里的功能,只需要傳入相應(yīng)的參數(shù)就可以。
validator.validate('測試名字', 'isNumber') // false
雖然可以得到理想的結(jié)果,但這種寫法有十分嚴(yán)重的缺點,最重要的,每次增加或修改規(guī)則時,需要修改整個validate函數(shù),這不符合開放封閉原則,增加邏輯,讓函數(shù)更加復(fù)雜不可控。
那真正適合的代碼應(yīng)該怎么寫呢?
var validator={
// 所有驗證規(guī)則處理函數(shù)存放的地方
types: {},
validate: function (str, types) {
this.messages=[];
var checker, result, msg, i;
for (i in types) {
var type=types[i];
checker=this.types[type]; // 獲取驗證規(guī)則的驗證類
if (!checker) { // 如果驗證規(guī)則類不存在,拋出異常
throw {
name: "ValidationError",
message: "No handler to validate type " + type
};
}
result=checker.validate(str); // 使用查到到的單個驗證類進(jìn)行驗證
if (!result) {
msg="Invalid value for *" + type + "*, " + checker.instructions;
this.messages.push(msg);
}
}
return this.hasErrors();
},
// 是否有message錯誤信息
hasErrors: function () {
return this.messages.length !==0;
}
};
復(fù)制代碼
上面的代碼定義了validator對象以及validate函數(shù),函數(shù)內(nèi)部會對傳入的字符串,檢測類型數(shù)組進(jìn)行處理。如果存在規(guī)則,進(jìn)行判斷,并把錯誤信息發(fā)送到this.message。如果不存在規(guī)則,自然的就不需要繼續(xù)執(zhí)行,拋出error即可。
// 驗證給定的值是否不為空
validator.types.isNonEmpty={
validate: function (value) {
return value !=="";
},
instructions: "傳入的值不能為空"
};
// 驗證給定的值是否 不是 純數(shù)字
validator.types.isNoNumber={
validate: function (value) {
return isNaN(value); // 偽寫法,因為isNaN會誤判布爾值和空字符串等,因此并不能作為真正判斷純數(shù)字的依據(jù)
},
instructions: "傳入的值不能是純數(shù)字"
};
// 驗證給定的值是否存在
validator.types.isExist={
validate: function (value) {
// $.ajax() ...
return true;
},
instructions: "給定的值已經(jīng)存在"
};
// 驗證給定的值長度是否合理
validator.types.isLength={
validate: function (value) {
var l=value.toString().length
if ( l > 2 && l < 10) {
return true;
} else {
return false;
}
},
instructions: "長度不合理,請長度在2-10個字符內(nèi)"
};
復(fù)制代碼
上面對types規(guī)則進(jìn)行了補充,定義了幾種規(guī)則,至此,對于名稱校驗,簡單的設(shè)定就敲完了。接下來要準(zhǔn)備的就是一個能夠在英雄聯(lián)盟合理的名字進(jìn)行驗證:
var types=['isExist', 'isLength', 'isNoNumber', 'isNonEmpty']; // 決定想要的規(guī)則,無論增加或者減少,原函數(shù)都不需要改動
function check (name, types) {
validator.validate(name, types);
if (validator.hasErrors()) {
console.log(validator.messages.join("\n"));
} else {
console.log('驗證通過!')
}
}
check('okckokckokck', types) // 長度不合理,請長度在2-10個字符內(nèi)
check('老faker', types) // true
check('00001', types) // 傳入的值不能是純數(shù)字
復(fù)制代碼
首先設(shè)定好想要的規(guī)則,用一個types數(shù)組囊括進(jìn)來,之后定義一個check函數(shù),把結(jié)果處理封裝一下,最后傳入?yún)?shù),無論想要檢測什么規(guī)則,都不需要修改原函數(shù)。現(xiàn)在無論我想檢測faker可不可以注冊,還是一個空字符串,都可以傳入規(guī)則,進(jìn)行使用。如果想添加新的規(guī)則,只需要在validator.types上續(xù)寫對象就可以,方便清晰,結(jié)構(gòu)明朗。
核心思想就是把復(fù)雜的算法結(jié)構(gòu),分別封裝起來,讓他們之間可以互相替換,上面的代碼就很好的體現(xiàn)了 互相替換 ,因為無論我怎么去修改想要的規(guī)則,都不需要改動原本的代碼。
在系統(tǒng)沿著多個維度變化的同時,又不增加其復(fù)雜度并已達(dá)到解耦。將抽象部分與它的實現(xiàn)部分分離,使它們都可以獨立地變化。簡單的說:橋接模式最主要的特點是實現(xiàn)層(如元素綁定的事件)與抽象層(如修飾頁面UI邏輯)解耦分離。
下面依然是一個例子:
假如我們還在英雄聯(lián)盟的世界里,每一場游戲最終都會有一個結(jié)局,無論勝利還是失敗,都會彈出一個窗口,告訴你 —— Victory或者是Defeat。
function GameMessage (type) { // 抽象 與 實現(xiàn) 的 橋梁
this.fn=type ? new Victory() : new Defeat()
}
GameMessage.prototype.show=function() {
this.fn.show()
}
function Defeat() { // 抽象層
this.show=function() {
console.log('im loser')
}
}
function Victory() { // 抽象層
this.show=function() {
console.log('im winner')
}
}
// 實現(xiàn)層
function getResult() {
var switchVD=Math.ceil(Math.random()*10) > 5 // 勝利失敗一半一半
return new GameMessage(switchVD)
}
var result1=getResult()
var result2=getResult()
var result3=getResult()
result1.show()
result2.show()
result3.show()
復(fù)制代碼
首先我們創(chuàng)建了一個GameMessage的函數(shù),我們都知道勝利失敗都有一半的概率,因此定義了switchVD變量,模擬一個隨機事件,同時每次結(jié)果調(diào)用一次getResult函數(shù),獲取最新結(jié)果。
橋接模式體現(xiàn)在GameMessage函數(shù)上,將抽象的 Victory() 以及 Defeat() 與 我們獲取結(jié)果的 getResult() 實現(xiàn)解耦。函數(shù)之間不糅合邏輯,但又通過橋梁函數(shù),連接在一起。
這么寫的好處就是,兩者都可以獨立的變化,互不打擾。畢竟如果揉在一起,可能邏輯如下:
function Defeat() { // 抽象層
this.show=function() {
console.log('im loser')
}
}
function Victory() { // 抽象層
this.show=function() {
console.log('im winner')
}
}
var switchVD=Math.ceil(Math.random()*10) > 5
if (switchVD) {
var result=new Victory()
} else {
var result=new Defeat()
}
result.show() // loser or winner
復(fù)制代碼
上述代碼可以輕松的看到,如果沒有橋接模式,直接把實現(xiàn)層,渲染層糅合在一起,會依賴上下文。倘若獲取不到上下文的環(huán)境,很容易出現(xiàn)問題。
橋接模式在日常開發(fā)中,會在不經(jīng)意間頻繁使用,目的也是為了讓代碼結(jié)構(gòu)清晰,將不同邏輯的代碼互相解耦。便于日后維護(hù),開發(fā)時也更能區(qū)分模塊,看的舒服,自然效率也高。
橋接模式關(guān)鍵是要理解抽象部分與實現(xiàn)部分的分離,使得二者可以獨立的變化,而不必拘泥于形式。靈活的變化,適用場景的多變就非常適合使用這種模式來實現(xiàn)。橋接模式最重要的是找到代碼中不同的變化緯度。
狀態(tài)模式(State)允許一個對象在其內(nèi)部狀態(tài)改變的時候改變它的行為,對象看起來似乎修改了它的類。 其實就是用一個對象或者數(shù)組記錄一組狀態(tài),每個狀態(tài)對應(yīng)一個實現(xiàn),實現(xiàn)的時候根據(jù)狀態(tài)挨個去運行實現(xiàn)。
優(yōu)點:
缺點:
比如下面我們定義一個英雄的狀態(tài),名字叫亞索,其中亞索可能同時有好幾個狀態(tài)比如 邊走邊攻擊 —— 我們俗稱的“走A”,還有可能釋放技能之后接一個“B鍵回家”的操作,當(dāng)然最有可能的是eqw閃r行云流水的操作收獲一個人頭,再接一個ctrl+f6等。
如果對這些操作一個個進(jìn)行處理判斷,需要多個if-else或switch不僅丑陋不說,而且在遇到有組合動作的時候,實現(xiàn)就會更為冗余。那么我們這里的復(fù)雜操作,可以使用 狀態(tài)模式 來實現(xiàn)。
狀態(tài)模式 的思路是:首先創(chuàng)建一個狀態(tài)對象或者數(shù)組,在對象內(nèi)部存儲需要操作的狀態(tài)數(shù)組或?qū)ο螅缓鬆顟B(tài)對象提供一些接口,可以更改狀態(tài)以及執(zhí)行動作。
那現(xiàn)在有一個英雄叫做亞索!下面代碼,我們就用亞索的狀態(tài)來實現(xiàn)一下傳說中的狀態(tài)模式:
function YasuoState() {
//存儲當(dāng)前即將執(zhí)行動作的狀態(tài)!
this.currentstate=[];
this.Actions={
walk : function(){
console.log('walk');
},
attack : function(){
console.log('attack');
},
magic : function(){
console.log('magic');
},
backhome : function(){
console.log('backhome');
}
};
}
YasuoState.prototype.changeState=function() {
//清空當(dāng)前的動作
this.currentstate=[];
Object.keys(arguments).forEach((i)=> this.currentstate.push(arguments[i]))
return this;
}
YasuoState.prototype.YasuoActions=function() {
//當(dāng)前動作集合中的動作依次執(zhí)行
this.currentstate.forEach((k)=> this.Actions[k] && this.Actions[k]())
return this;
}
var yasuoState=new YasuoState();
yasuoState.changeState('walk','attack').YasuoActions().changeState('walk').YasuoActions().YasuoActions();
復(fù)制代碼
上面代碼成功實現(xiàn)了亞索的狀態(tài)模式,我們假設(shè)他有走路、攻擊、釋放技能、回家?guī)讉€狀態(tài),其中這幾個狀態(tài)其實是可以同時輸入指令的,要不然那些職業(yè)選手的高光操作就會在 技能銜接 而出現(xiàn)的卡頓 香消玉殞。
狀態(tài)模式最常見的就是日常的例子 —— 紅綠燈,每當(dāng)切換狀態(tài)的時候,執(zhí)行一次動作。
至于英雄聯(lián)盟中,最常見的就是邊走邊攻擊,在輸入命令后,首先改變了我們對象的狀態(tài)yasuoState.changeState('magic','backhome'),然后因為在代碼中有return this;,可以鏈?zhǔn)秸{(diào)用接下來的行為,于是我們讓它依次執(zhí)行剛才輸入的狀態(tài)。接下來又一次改變了狀態(tài)changeState('walk'),并且進(jìn)行執(zhí)行。可以看到執(zhí)行了兩次,由于狀態(tài)并沒有再次改變,因此只需要重復(fù)執(zhí)行就可以保證我們的英雄一直往前走下去了。
希望狀態(tài)模式可以幫助你解決絕大多數(shù),需要切換狀態(tài)的操作。遇到類似的問題時,可以迅速拿出成熟可靠的狀態(tài)模式解決之。
本次分享的三種模式,都可以在英雄聯(lián)盟中找到影子,因為我喜歡這款游戲,所以很輕松可以找到其中使用的設(shè)計模式:
設(shè)計模式主要可以幫助我們解決,開發(fā)中對代碼的設(shè)計問題,那我們?nèi)绾握业胶线m的對象,并應(yīng)用合適的設(shè)計模式呢?
借用書中的幾個提示吧:
尋找合適的對象
決定對象的粒度
決定好這個對象設(shè)計的接口
把對象需要的具體函數(shù)實現(xiàn)
合理的運用代碼復(fù)用機制
設(shè)計的代碼應(yīng)該可以支持變化,要對變化有預(yù)見性
大概是這幾種,在 javascript 中涉及編譯的場景較少,就不敘述了。
設(shè)計模式是軟件開發(fā)人員在軟件開發(fā)過程中面臨的一般問題的解決方案。這些解決方案是眾多軟件開發(fā)人員經(jīng)過相當(dāng)長的一段時間的試驗和錯誤總結(jié)出來的。
根據(jù)上面的幾條規(guī)則,在開發(fā)接口和函數(shù)的時候,時刻注意,就可以避免大多數(shù)代碼設(shè)計上的問題,對于以后的維護(hù)也會有巨大的幫助。下一個接受代碼的人,也會十分感激你的,讀代碼其實和讀書一樣,你現(xiàn)在偷懶寫的代碼可能無所謂,后面接手的人會瘋狂吐槽。相反如果你優(yōu)雅的實現(xiàn),像我,就會心里由衷的佩服,看到整齊的函數(shù),注釋明朗的功能,不得不說,高手確實是高手啊,短短 200 行,讓人跪服,就突出一個詞 —— 優(yōu)雅。
作者:黃梵高
鏈接:https://juejin.im/post/5ec791fdf265da770d3daabd
*請認(rèn)真填寫需求信息,我們會在24小時內(nèi)與您取得聯(lián)系。