在實際開發中,可能會遇到這樣一個情況,某一功能的實現分為多種算法,這些算法可以認定為策略,在實際操作時選擇不同算法或策略進行操作得出最終結果。在實際生活中,這些例子也是舉不勝舉,例如,商場舉行活動,滿100元減10元,滿200元減30元,滿500元減100元等等...這樣每消費一筆,根據這一筆錢消費的多少,計算最終應支付的錢對應著不同的算法,這些對應的不同計算方法就可以認定為是不同的策略。在某東購物時,根據不同的用戶等級,打折力度也是不同的。
策略模式的UML類圖參照下圖:
假如沒有策略模式,實現某東購物計算最終付款的方法怎樣呢?
package com.strategy.demo; public class NoStrategy { /** * 不使用測量模式實現 * @param args */ private static final int NOCARDUSER=1; private static final int IRONCARDUSER=2; private static final int GOLDCARDUSER=3; public static void main(String[] args) { NoStrategy NoStrategy1=new NoStrategy(); NoStrategy NoStrategy2=new NoStrategy(); NoStrategy NoStrategy3=new NoStrategy(); System.out.println("沒有卡牌的買家買100元貨物最終應付款:"+NoStrategy1.getPrice(100.0, 1)); System.out.println("鐵牌的買家買100元貨物最終應付款:"+NoStrategy2.getPrice(100.0, 2)); System.out.println("金牌的買家買100元貨物最終應付款:"+NoStrategy3.getPrice(100.0, 3)); } private double getNoCardPrice(double price){ return price; } private double getIronCardPrice(double price){ return price*0.9; } private double getGoldCardPrice(double price){ return price*0.7; } private double getPrice(double price,int type){ if(type==NOCARDUSER){ return getNoCardPrice(price); }else if(type ==IRONCARDUSER){ return getIronCardPrice(price); }else if(type ==GOLDCARDUSER){ return getGoldCardPrice(price); }else { return 0; } } }
運行實例:
呀,得出正確的答案了,這時你是不是應該滿足了呢,應該高枕無憂了呢?突然,主管說要增加鑽石用戶的類別,鑽石用戶打六折,這時你怎麼實現呢?在裡面在增加鑽石用戶的類型,再增加計算鑽石用戶的方法,再再最後的判斷裡增加i f else? 這樣的確可以實現功能,但是是不是不滿足開閉原則呢?而且隨著用戶種類的不斷增加,你的if else是不是也越來越長,邏輯也越來越復雜呢?導致系統擴展性和穩定性越來越差呢? 所以,這種方式在實際中顯然實不可取的,下面我們看一下如何使用策略模式來實現上面的需求。
1.PriceStrategyInterface 接口,對應UML類圖中的Strategy接口:
package com.strategy.demo; public interface PriceStrategyInterface { double calPrice(double price); }
2.實現類,無卡用戶:
package com.strategy.demo; public class NoCardUserStrategy implements PriceStrategyInterface { /** * 無牌買家,原價 */ @Override public double calPrice(double price) { return price; } }
3.實現類,鐵卡用戶:
package com.strategy.demo; public class IronCardUserStrategy implements PriceStrategyInterface { /* * 鐵牌買家 * (non-Javadoc) * @see com.strategy.demo.PriceStrategyInterface#calPrice(double) */ @Override public double calPrice(double price) { return price*0.9; } }
4.實現類,金卡用戶:
package com.strategy.demo; public class GoldCardUserStrategy implements PriceStrategyInterface { /** * 金牌買家 */ @Override public double calPrice(double price) { return price*0.7; } }
5.環境對象,用來操作策略:
package com.strategy.demo; public class PriceContext { /** * 操作類 */ PriceStrategyInterface priceStrategyInterface; /* * 通過初始化傳入對象 */ public PriceContext(PriceStrategyInterface priceStrategyInterface) { this.priceStrategyInterface=priceStrategyInterface; } /* * 通過對象計算返回值 */ public double getPrice(double price){ return priceStrategyInterface.calPrice(price); } }
環境對象初始化時,將對應的策略對象傳入,然後調用方法返回計算值。
6.構建測試類,測試:
package com.strategy.demo; public class TestClass { public static void main(String[] args) { PriceContext priceContext=new PriceContext(new NoCardUserStrategy()); System.out.println("沒有卡牌的買家買100元貨物最終應付款:"+priceContext.getPrice(100.0)); PriceContext priceContext2=new PriceContext(new IronCardUserStrategy()); System.out.println("鐵牌的買家買100元貨物最終應付款:"+priceContext2.getPrice(100.0)); PriceContext priceContext3=new PriceContext(new GoldCardUserStrategy()); System.out.println("金牌的買家買100元貨物最終應付款:"+priceContext3.getPrice(100.0)); } }
運行上面的實例:
得到了和第一個方法一樣的正確答案,這時我們假如要增加一個鑽石買家的種類,怎麼實現呢?我們只需要增加一個策略實現類:
package com.strategy.demo; public class DiamondUserStrategy implements PriceStrategyInterface { @Override public double calPrice(double price) { return price*0.6; } }
然後測試類增加一條鑽石類買家的購物:
package com.strategy.demo; public class TestClass { public static void main(String[] args) { PriceContext priceContext=new PriceContext(new NoCardUserStrategy()); System.out.println("沒有卡牌的買家買100元貨物最終應付款:"+priceContext.getPrice(100.0)); PriceContext priceContext2=new PriceContext(new IronCardUserStrategy()); System.out.println("鐵牌的買家買100元貨物最終應付款:"+priceContext2.getPrice(100.0)); PriceContext priceContext3=new PriceContext(new GoldCardUserStrategy()); System.out.println("金牌的買家買100元貨物最終應付款:"+priceContext3.getPrice(100.0)); PriceContext priceContext4=new PriceContext(new DiamondUserStrategy()); System.out.println("鑽石卡的買家買100元貨物最終應付款:"+priceContext4.getPrice(100.0)); } }
運行實例:
是不是擴展起來特別容易?條理也十分清晰。總結一下策略模式的優點:
1. 結構清晰,使用簡單直觀;
2. 系統耦合性降低,擴展方便;
3. 操作封裝徹底,數據更為安全。(在TestClass中,只知道相關實現類,並不涉及具體計算方法)
當然,策略方式也存在一定的缺點:
由圖可以直觀的看出,隨著策略的不斷增加,子類數量變得龐大。