JAVA設計模式什麼鬼(策略)——作者:凸凹裡歐
策略,Strategy,古時也稱“計”,為了達成某個目標的方案,目標不同,方案也隨之更改。例如特工執行任務時總要準備好幾套方案以應對突如其來的變化,A計劃實施過程中情況突變導致預案無法繼續實施,則馬上更換為B計劃,正所謂計劃不如變化快,提前策劃固然非常重要,而隨機應變更是不可或缺,只有保證這種可變的靈活性才能立於不敗之地。世界永遠都在變,唯一不變的就是變本身。
作為有思想的碼農,我們當然也不能把程式寫死了,一個設計優秀的系統,絕不是把現有類的程式碼改來改去,而一定是擴充套件類並接入系統,這樣馬上就能適應不同的使用者需求。
就拿遊戲機來舉個例子,早期的俄羅斯方塊風靡全球,後來國內流行一種掌機,只能玩俄羅斯方塊這一個遊戲,可過不了多久大家就玩膩了,於是熱度降低這種遊戲機很快就退出市場了,顯然這是一種失敗的設計模式。
後來任天堂出品的Game Boy以及Sony的PSP則完全帶來了不同的使用者體驗,系統提供了統一的卡槽介面,玩家只要更換卡帶或MD就可以達到更換遊戲的目的,做到了一機多用。
各種遊戲卡帶,更換遊戲方便多了。
好了,開始實戰部分,為了說明問題,我們繼續發揚極簡主義的優良傳統,我們就做一個最簡單的計算器好了,假設我們的計算器只能進行加減法,程式碼如下。
1 public class Calculator {//違反設計模式原則的做法 2 public int add(int a, int b){//加法 3 return a + b; 4 } 5 6 public int sub(int a, int b){//減法 7 return a - b; 8 } 9 }
這樣寫ok嗎?我們往後的擴充套件想想,如果隨著我們的演算法不斷增加,如乘法、除法、次方、開方等等,那麼這個計算器類就得不斷的改啊改啊,每次升級演算法我們都要把機器給拆開然後更改類程式碼,這豈不是作死?改到最後這個龐大的系統會不會變化這樣?
或者是……如這般瘋狂?
作死!的確是作死!我們來換個思路,先思考一下,既然不能把演算法給寫死在這裡面,那一定要把這個演算法給抽象一下,把實現細節從這個類裡抽離出來,獨立出來成為n個策略,就當下來講我們一共有倆個策略,一個是加法策略,一個是減法策略,他們實現的都是同一個演算法介面,接收引數為運算元a,以及被運算元b。
public interface Strategy {//演算法標準 public int calculate(int a, int b);//運算元,被運算元 }
下來實現加法策略、減法策略。
public class Addition implements Strategy{//實現演算法介面
@Override
public int calculate(int a, int b) {//加數與被加數
return a + b;//這裡我們做加法運算
}
}
public class Subtraction implements Strategy{//實現演算法介面
@Override
public int calculate(int a, int b) {//減數與被減數
return a - b;//這裡我們做減法運算
}
}
演算法寫好了,開始寫計算器。
1 public class Calculator {//計算器類
2 private Strategy strategy;//擁有某種演算法策略
3
4 public void setStrategy(Strategy strategy) {//接入演算法策略
5 this.strategy = strategy;
6 }
7
8 public int getResult(int a, int b){
9 return this.strategy.calculate(a, b);//返回具體策略的結果
10 }
11 }
可以看到,計算器類裡已經把之前的具體加減演算法實現程式碼給剝離出去了,要用哪個演算法,只需要注入進來,然後獲得計算結果getResult實際上呼叫的是具體演算法的calculate,我們來看怎樣使用這個計算器。
1 public class Client {
2 public static void main(String[] args) {
3 Calculator calculator = new Calculator();//例項化計算器
4 calculator.setStrategy(new Addition());//接入加法實現
5 int result = calculator.getResult(1, 1);//計算!
6 System.out.println(result);//得到的是加法結果2
7
8 calculator.setStrategy(new Subtraction());//再次接入減法實現
9 result = calculator.getResult(1, 1);//計算!
10 System.out.println(result);//得到的是減法結果0
11
12 }
13 }
註釋已經寫得非常明白了,相信大家都看懂了吧。那麼我們這個計算器可以說是具有演算法策略擴充套件性的,以後要有新的演算法是不需要再更改任何現有程式碼的,只需要新寫一個演算法比如乘法Multiplication,並實現calculate方法,接下來要做的只是組裝上去便可以使用了。
計算器可以搞策略,那計算機呢?還記得我們在《設計模式是什麼鬼(初探)》中舉的計算機例子吧?很顯然是同樣是策略模式,大家可以自行寫碼試煉。
從以上的幾個例子可以看出,我們的策略模式獲得了極大的應用,策略實現類已經成為獨立於宿主之外的模組,即插即用。可以組合成為一個整體,又可以分拆獨立,可以發生關聯,但絕不耦合,既對立又統一,這是唯物辯證法的絕佳體現。