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