歡迎收看俗到掉渣的《小Y講堂》節目,大家好,我是小Y,一個集性感毛髮與才華於一身的程式猿。小Y的設計模式系列中的「狀態模式」和「策略模式」都已經總結完成了,很多小夥伴都會凌亂在這兩種模式當中,小Y曾經也被凌亂到無法自拔。。。
一、模式對戰前的準備
兩個類圖都非常相似,都是通過Context類封裝了一個具體的行為,都提供了一個封裝方法,是高擴充套件性的設計模式。它們就像一對孿生兄弟一樣,通過通用UML根本沒有辦法區分出不同之處。小Y舉個例子來區分它們之間的不同點。
小Y玩《魂鬥羅歸來》有自己的一套方法和習慣,每次都會按照先闖關卡對戰☞1vs1對戰模式☞3vs3對戰模式的順序來進行遊戲衝關(突然感覺小Y的強迫症在加重...)。1vs1、3vs3、關卡對戰至關重要的一點就是要選擇武器,1vs1模式選擇的武器就是狙擊槍+噴射器,3vs3模式選擇的武器是炮類+突擊步槍,關卡對戰選擇的武器是機關槍+突擊步槍。按照策略模式來分析,根據三種對戰模式選擇武器就是三個不同的具體演算法,演算法之間沒有互動,以達到演算法可以自由切換,隨著不同的對戰模式而進行武器的更換;按照狀態模式來分析,小Y的打遊戲的順序(關卡對戰☞1vs1對戰模式☞3vs3對戰模式)就被看做三個不同的狀態,每個狀態的改變,就會引起行為的變化,同時每個狀態的變化都會指定下一個狀態。
二、策略模式實現武器切換
1.策略模式武器切換類圖
2.切換的程式碼清單
①武器切換抽象類
public abstract class ISwitch {
public abstract void switch();
}
複製程式碼
②關卡對戰模式
public class BarrierFight extends ISwitch {
public void switch() {
System.out.println("BillRizer選擇的武器:機關槍+突擊步槍");
}
}
複製程式碼
③1vs1對戰模式
public class OnetoOneFight extends ISwitch {
public void switch() {
System.out.println("BillRizer選擇的武器:狙擊槍+噴射器");
}
}
複製程式碼
④3vs3對戰模式
public class ThreetoThreeFight extends ISwitch {
public void switch() {
System.out.println("BillRizer選擇的武器:炮類+突擊步槍");
}
}
複製程式碼
⑤對戰模式
public class Context {
//建構函式,要使用玩哪種模式
private ISwitch switchStrategy;
public Context(ISwitch switchStrategy){
this.SwitchStrategy = switchStrategy;
}
//根據不同模式選擇不同武器
public void switch(){
this.switchStrategy.switch();
}
}
複製程式碼
⑥使用不同武器
public class xiaoY {
//小Y開始打遊戲了,根據不同模式選擇了不同的武器
public static void main(String[] args) {
Context context;
//關卡對戰模式
context = new Context(new BarrierFight());
context.switch();
//1vs1對戰
context = new Context(new OnetoOneFight());
context.switch();
//3vs3對戰模式
context = new Context(new ThreetoThreeFight());
context.switch();
}
}
複製程式碼
輸出的結果為:
①BillRizer選擇的武器:機關槍+突擊步槍
②BillRizer選擇的武器:狙擊槍+噴射器
③BillRizer選擇的武器:炮類+突擊步槍
複製程式碼
三、狀態模式實現武器切換
1.狀態模式武器切換類圖 [站外圖片上傳中...(image-53dff0-1509702367313)] 2.切換的程式碼清單
①武器切換抽象類
public abstract class ISwitch {
protected Context context;
public void setContext(Context context){
this.context=context;
}
public abstract void switch();
}
複製程式碼
②關卡對戰模式
public class BarrierFight extends ISwitch {
public void switch() {
System.out.println("BillRizer選擇的武器:機關槍+突擊步槍");
super.context.setState(ONE_FIGHT_STATE);
}
}
複製程式碼
③1vs1對戰模式
public class OnetoOneFight extends ISwitch {
public void switch() {
System.out.println("BillRizer選擇的武器:狙擊槍+噴射器");
super.context.setState(THREE_FIGHT_STATE);
}
}
複製程式碼
④3vs3對戰模式
public class ThreetoThreeFight extends ISwitch {
public void switch() {
System.out.println("BillRizer選擇的武器:炮類+突擊步槍");
}
}
複製程式碼
⑤對戰模式
public class Context {
//定義對戰的幾種模式
public static final ISwitch BARRIER_FIGHT_STATE=new BarrierFight();
public static final ISwitch ONE_FIGHT_STATE=new OnetoOneFight();
public static final ISwitch THREE_FIGHT_STATE=new ThreetoThreeFight();
private ISwitch switchState;
public void setState(ISwitch switchState){
this.switchState = switchState;
this.switchState.setContext(this);
}
//根據不同模式選擇不同武器
public void switch(){
this.switchState.switch();
}
}
複製程式碼
⑥使用不同武器
public class BillRizer {
//比爾.雷澤出場了,他根據不同模式選擇了不同的武器
public static void main(String[] args) {
Context context;
context = new Context();
//關卡對戰模式
context.setState(new BarrierFight());
context.switch();
//1vs1對戰
context.switch();
//3vs3對戰模式
context.switch();
}
}
複製程式碼
輸出的結果為:
①BillRizer選擇的武器:機關槍+突擊步槍
②BillRizer選擇的武器:狙擊槍+噴射器
③BillRizer選擇的武器:炮類+突擊步槍
複製程式碼
兩種模式執行的結果都是相同的,但是兩者的分析角度是大相徑庭的,實現通過採用策略模式實現了“切換武器”這個策略的三種不同演算法,演算法可以自由切換,到底用哪個演算法由呼叫者決定,因此策略模式的使用重點是演算法的自由切換,增加新的演算法對整體功能沒有非常大的改變,非常靈活;而狀態模式是從小Y打遊戲闖關的順序來分析,每個關卡代表的狀態對應了不同的行為,狀態改變後行為也隨之改變,每個狀態的變化都會指定下一個狀態。
三、小結
從以上示例中我們也可以看出,對於相同的業務需求,有很多種實現方法,問題的重點是業務關注的是什麼,只有找準了業務的焦點,才能夠選擇更加合適的設計模式。
雖然我們從通用UML圖上稱他們為親兄弟,但是從上面的兩個程式碼清單可以看出這兩者還是存在著非常大的差別,很容易區分出來。
-
策略模式演算法可以自由切換,到底用哪個演算法由呼叫者決定;狀態模式是初始化一個狀態,之後的每個狀態的變化都會指定下一個狀態。
-
環境角色的職責不同。兩者都有一個叫做Context環境角色的類,但是兩者的區別很大,策略模式的環境角色只是一個委託作用,負責演算法的替換;而狀態模式的環境角色不僅僅是委託行為,它還具有登記狀態變化的功能,與具體的狀態類協作,共同完成狀態切換行為隨之切換的任務。
-
應用場景不同。,策略模式只是一個演算法的封裝,可以是一個有意義的物件,也可以是一個無意義的邏輯片段;狀態模式則要求有一系列狀態發生變化的場景,它要求的是有狀態且有行為的場景。
-
解決問題的方法不同。策略模式只是確保演算法可以自由切換,但是什麼時候用什麼演算法它決定不了;狀態模式對外暴露的是行為,狀態的變化一般是由環境角色和具體狀態共同完成的。
簡書地址:http://www.jianshu.com/p/ac5b81102e9c