簡說設計模式——策略模式

1、什麼是策略模式

  策略這個詞應該怎麼理解,打個比方說,咱們出門的時候會選擇不一樣的出行方式,好比騎自行車、坐公交、坐火車、坐飛機、坐火箭等等,這些出行方式,每一種都是一個策略。git

  再好比咱們去逛商場,商場如今正在搞活動,有打折的、有滿減的、有返利的等等,其實無論商場如何進行促銷,說到底都是一些算法,這些算法自己只是一種策略,而且這些算法是隨時均可能互相替換的,好比針對同一件商品,今天打八折、明天滿100減30,這些策略間是能夠互換的。算法

  策略模式(Strategy),定義了一組算法,將每一個算法都封裝起來,而且使它們之間能夠互換。UML結構圖以下:ide

  其中,Context是上下文,用一個ConcreteStrategy來配置,維護一個對Strategy對象的引用;Strategy是策略類,用於定義全部支持算法的公共接口;ConcreteStrategy是具體策略類,封裝了具體的算法或行爲,繼承於Strategy。佈局

  1. Context上下文

  Context上下文角色,也叫Context封裝角色,起承上啓下的做用,屏蔽高層模塊對策略、算法的直接訪問,封裝可能存在的變化。測試

 1 public class Context {
 2     
 3     Strategy strategy;
 4     
 5     public Context(Strategy strategy) {
 6         this.strategy = strategy;
 7     }
 8     
 9     //上下文接口
10     public void contextInterface() {
11         strategy.algorithmInterface();
12     }
13 
14 }

  2. 策略角色

  抽象策略角色,是對策略、算法家族的抽象,一般爲接口,定義每一個策略或算法必須具備的方法和屬性。algorithm是「運算法則」的意思。this

1 public abstract class Strategy {
2     
3     //算法方法
4     public abstract void algorithmInterface();
5 
6 }

  3. 具體策略角色

  用於實現抽象策略中的操做,即實現具體的算法,下方用print代替。測試類共3個ConcreteStrategy,其它兩個類與ConcreteStrategyA同理,就再也不贅述了。spa

1 public class ConcreteStrategyA extends Strategy {
2 
3     @Override
4     public void algorithmInterface() {
5         System.out.println("算法A實現");
6     }
7 
8 }

  4. Client客戶端

  下面依次更換策略,測試一下策略模式。code

 1 public class Client {
 2     
 3     public static void main(String[] args) {
 4         Context context;
 5         
 6         context = new Context(new ConcreteStrategyA());
 7         context.contextInterface();
 8         
 9         context = new Context(new ConcreteStrategyB());
10         context.contextInterface();
11         
12         context = new Context(new ConcreteStrategyC());
13         context.contextInterface();
14     }
15 
16 }

  運行結果以下:orm

  

2、策略模式的應用

  1. 什麼時候使用

  • 一個系統有許多類,而區分它們的只是他們直接的行爲時

  2. 方法

  • 將這些算法封裝成一個一個的類,任意的替換

  3. 優勢

  • 算法能夠自由切換
  • 避免使用多重條件判斷(若是不用策略模式咱們可能會使用多重條件語句,不利於維護)
  • 擴展性良好,增長一個策略只需實現接口便可

  4. 缺點

  • 策略類數量會增多,每一個策略都是一個類,複用的可能性很小
  • 全部的策略類都須要對外暴露

  5. 使用場景

  • 多個類只有算法或行爲上稍有不一樣的場景
  • 算法須要自由切換的場景
  • 須要屏蔽算法規則的場景

  6. 應用實例

  • 出行方式,自行車、汽車等,每一種出行方式都是一個策略
  • 商場促銷方式,打折、滿減等
  • Java AWT中的LayoutManager,即佈局管理器

  7. 注意事項

  • 若是一個系統的策略多於四個,就須要考慮使用混合模式來解決策略類膨脹的問題

3、策略模式的實現

  下面就以商場促銷爲例使用策略模式實現商場促銷算法。UML圖以下:對象

  1. 上下文類

  首先聲明一個CashSuper對象,經過構造方法,傳入具體的收費策略,getResult()方法的功能爲根據收費策略的不一樣得到計算結果。

 1 public class CashContext {
 2     
 3     private CashSuper cashSuper;
 4     
 5     public CashContext(CashSuper cashSuper) {
 6         this.cashSuper = cashSuper;
 7     }
 8     
 9     public double getResult(double money) {
10         return cashSuper.acceptCash(money);
11     }
12 
13 }

  2. 現金收費抽象類

  策略類,爲抽象類,抽象出收費的方法供子類實現。

1 public abstract class CashSuper {
2     
3     public abstract double acceptCash(double money);
4 
5 }

  3. 正常收費子類

  沒有任何活動的狀況,正常收費,返回原價。

1 public class CashNormal extends CashSuper {
2 
3     @Override
4     public double acceptCash(double money) {
5         return money;
6     }
7 
8 }

  4. 打折收費子類

  打折活動,根據折扣返回打折後的價格。

 1 public class CashRebate extends CashSuper {
 2     
 3     private double moneyRebate = 1;    //折扣
 4     
 5     public CashRebate(double moneyRebate) {
 6         this.moneyRebate = moneyRebate;
 7     }
 8 
 9     @Override
10     public double acceptCash(double money) {
11         return money * moneyRebate;
12     }
13 
14 }

  5. 返利收費子類

  返利活動,輸入返利條件和返利值,好比滿300返100,moneyCoditation爲300,moneyReturn爲100。

   result = money - Math.floor(money / moneyConditation) * moneyReturn; 的意思爲,若是當前金額大於等於返利條件,則使用當前金額減去返利值。

 1 public class CashReturn extends CashSuper {
 2 
 3     private double moneyConditation = 0.0;    //返利條件
 4     private double moneyReturn = 0.0d;    //返利值
 5     
 6     public CashReturn(double moneyConditation, double moneyReturn) {
 7         this.moneyConditation = moneyConditation;
 8         this.moneyReturn = moneyReturn;
 9     }
10 
11     @Override
12     public double acceptCash(double money) {
13         double result = money;
14         
15         if (money >= moneyConditation) {
16             result = money - Math.floor(money / moneyConditation) * moneyReturn;
17         }
18         
19         return result;
20     }
21 
22 }

  6. Client客戶端

  下面寫一個簡單的程序測試一下上方編寫的代碼。

 1 public class Client {
 2     
 3     public static void main(String[] args) {
 4         CashContext cashContext = null;
 5         
 6         Scanner scanner = new Scanner(System.in);
 7         System.out.print("請輸入打折方式(1/2/3):");
 8         int in = scanner.nextInt();
 9         String type = "";
10         
11         switch (in) {
12             case 1:
13                 cashContext = new CashContext(new CashNormal());
14                 type += "正常收費";
15                 break;
16                 
17             case 2:
18                 cashContext = new CashContext(new CashReturn(300, 100));
19                 type += "滿300返100";
20                 break;
21                 
22             case 3:
23                 cashContext = new CashContext(new CashRebate(0.8));
24                 type += "打8折";
25                 break;
26     
27             default:
28                 System.out.println("請輸入1/2/3");
29                 break;
30         }
31         
32         double totalPrices = 0;
33         
34         System.out.print("請輸入單價:");
35         double price = scanner.nextDouble();
36         System.out.print("請輸入數量:");
37         double num = scanner.nextDouble();
38         totalPrices = cashContext.getResult(price * num);
39         
40         System.out.println("單價:" + price + ",數量:" + num + ",類型:" + type + ",合計:" + totalPrices);
41         
42         scanner.close();
43     }
44 
45 }

  正常收費結果以下:

  

  返利收費結果以下:

  

  打折收費結果以下:

  

 

  源碼地址:https://gitee.com/adamjiangwh/GoF 

相關文章
相關標籤/搜索