C8) State(狀態(tài)模式) 定義:當(dāng)對(duì)象的內(nèi)部狀態(tài)發(fā)生變化時(shí),允許該對(duì)象改變其行為。對(duì)象看似換了一個(gè)類。 從前面的中介模式到觀察者模式到現(xiàn)在的這個(gè)狀態(tài)模式,一直都以對(duì)象的內(nèi)部狀態(tài)變化為出發(fā)點(diǎn)來考慮對(duì)對(duì)象行為的重新構(gòu)造,就這點(diǎn)來看,行為模式是以(對(duì)象類的)不變應(yīng)(對(duì)象內(nèi)部狀態(tài)的)萬變,確實(shí)非常巧妙。 接下來看看這個(gè)模式,我們?cè)谝粋€(gè)內(nèi)部狀態(tài)發(fā)生改變的時(shí)候,通常使用if...elseif...或者switch...case的分支語句加以判斷,再將對(duì)應(yīng)的不同行為表現(xiàn)出來,但這只適合簡(jiǎn)單的線性的變化,如果遇到非線性的場(chǎng)合,用分支語句就顯得捉襟見肘了。狀態(tài)模式從此孕育而生,將狀態(tài)變化部分從原有對(duì)象中分離出來,并讓狀態(tài)自己掌握向下一個(gè)狀態(tài)的變換的過程,從而使得原來的對(duì)象可以不用關(guān)心對(duì)其的控制問題。狀態(tài)變化越是復(fù)雜,這個(gè)模式的優(yōu)點(diǎn)越是明顯,Gof舉了TCP狀態(tài)的例子,可惜對(duì)TCP還不太了解,所以這里避重就輕,來個(gè)簡(jiǎn)單的例子。 游戲應(yīng)該都玩過,無非是賺經(jīng)驗(yàn)升級(jí),現(xiàn)在就拿這個(gè)來說明。一個(gè)角色,有一定經(jīng)驗(yàn)后可以轉(zhuǎn)職升級(jí),不同職業(yè)附加值不同,追加能力也不同,其他牽涉的屬性也可能不一樣。假設(shè)從無職業(yè)到戰(zhàn)士到劍士最后到騎士(似乎老土了點(diǎn)),這樣一個(gè)過程,職業(yè)就是狀態(tài),職業(yè)的改變影響了角色也就是對(duì)象的行為(能力值、攻擊方式等等)。定義職業(yè)的抽象類和具體實(shí)現(xiàn): public interface Career { public int ATK; public int DEF; public int HIT; public void Transfer(Role role); } public class Soldier implements Career { public Soldier() { ATK = 10; DEF = 10; HIT = 5; } public void Transfer(Role role) { role.addAttack(this.ATK); role.addDefense(this.DEF); role.addHit(this.HIT); role.setCareer(new Swordman()); } } public class Swordman implements Career { public Swordman() { ATK = 25; DEF = 15; HIT = 10; } public void Transfer(Role role) { role.addAttack(this.ATK); role.addDefense(this.DEF); role.addHit(this.HIT); role.setCareer(Knight()); } } public class Knight implements Career { public Knight() { ATK = 40; DEF = 40; HIT = 15; } public void Transfer(Role role) { role.addAttack(this.ATK); role.addDefense(this.DEF); role.addHit(this.HIT); } } 對(duì)角色對(duì)象的描述: public class Role { private int attack = 30; private int defense = 20; private int hit = 60; private Career career; public Role() { setCareer(new Soldier()); } public void setCareer(Career career) { this.career = career; } public void LevelUp() { career.Transfer(this); } } 得到的客戶端的調(diào)用 Role player = new Role(); player.GainExp(); player.LevelUp(); //now is Soldierman player.GainExp(); player.LevelUp(); //now is Swordman 上面只是簡(jiǎn)單的,用通常的方法也可以,但是如果職業(yè)變化復(fù)雜了(日系游戲的職業(yè)系統(tǒng)非常變態(tài)),用if...else...寫到最后可能連自己都分不清了。上面的代碼還有很多冗余部分,可以用外觀模式加以改進(jìn),變得更為簡(jiǎn)練。
參考: 1、 http://www./designpatterns/designpattern_State.htm(中文、java實(shí)例) 2、 http://www./Patterns/PatternState.aspx(英文、C#實(shí)例、UML) 3、 http://www.caterpillar./PmWiki/pmwiki.php/DesignPattern/StatePattern(中文、java實(shí)例、UML)推薦
|