设计模式(二十一)策略模式

1、策略模式(Strategy):定义了一组算法,将每个算法都封装其类,并且使他们之间可以互换。

 

2、UML结构图如下:

 

                                                             

 

   其中,Context是上下文,用一个ConcreteStrategy来配置,维护一个对Strategy对象的引用;Strategy是策略类,用于定义所有支持算法的公共接口;ConcreteStrategy是具体策略类,封装了具体的算法或行为,继承于Strategy。

 

3、使用场景

  •  多个类只有算法或行为上稍有不同的场景;
  • 算法需要自由切换的场景;
  • 需要屏蔽算法规则的场景。

 

4、优缺点

优点

  • 算法可以自由切换;
  • 避免使用多重条件判断(如果不用策略模式我们可能会使用多重条件语句,不利于维护);
  • 扩展性良好,增加一个策略只需实现接口即可。

缺点

  • 策略类数量会增多,每个策略都是一个类,复用的可能性很小;
  • 所有的策略类都需要对外暴露。

 

5、应用实例

  • 商场促销方式,打折、满减等;
  • 出行方式,自行车、汽车等,每一种出行方式都是一个策略;
  • Java AWT中的LayoutManager,即布局管理器。

 

6、注意事项

  • 如果一个系统的策略多于四个,就需要考虑使用混合模式来解决策略类膨胀的问题。

 

7、代码实例

(1)上下文类

  首先声明一个CashSuper对象,通过构造方法,传入具体的收费策略,getResult()方法的功能为根据收费策略的不同获得计算结果。

 1 /**
 2  * @author it-小林
 3  * @desc   上下文类
 4  * @date 2021年09月28日 9:57
 5  */
 6 public class CashContext {
 7 
 8     private CashSuper cashSuper;
 9 
10     public CashContext(CashSuper cashSuper) {
11         this.cashSuper = cashSuper;
12     }
13 
14     public double getResult(double money){
15         return cashSuper.acceptCash(money);
16     }
17 }

 

 

(2)现金收费抽象类

  策略类,为抽象类,抽象出收费的方法供子类实现。

 1 /**
 2  * @author it-小林
 3  * @desc   现金收费抽象类
 4  * @date 2021年09月28日 9:46
 5  */
 6 public abstract class CashSuper {
 7 
 8     public abstract double acceptCash(double money);
 9 
10 }

 

 

(3)正常收费子类

  没有任何活动的情况,正常收费,返回原价。

 1 /**
 2  * @author it-小林
 3  * @desc   正常收费子类
 4  * @date 2021年09月28日 9:48
 5  */
 6 public class CashNormal extends CashSuper{
 7 
 8 
 9     @Override
10     public double acceptCash(double money) {
11         return money;
12     }
13 }

 

 

(4)打折收费子类

  打折活动,根据折扣返回打折后的价格。

 1 /**
 2  * @author it-小林
 3  * @desc   打折收费子类
 4  * @date 2021年09月28日 9:49
 5  */
 6 public class CashRebate extends CashSuper {
 7 
 8     private double moneyRebate = 1; //折扣
 9 
10     public CashRebate(double moneyRebate) {
11         this.moneyRebate = moneyRebate;
12     }
13 
14     @Override
15     public double acceptCash(double money) {
16         return money * moneyRebate;
17     }
18 }

 

 

 (5)返利收费子类

返利活动,输入返利条件和返利值,比如满300返100,moneyCoditation为300,moneyReturn为100。

   result = money - Math.floor(money / moneyConditation) * moneyReturn; 的意思为,如果当前金额大于等于返利条件,则使用当前金额减去返利值。

 

 1 /**
 2  * @author it-小林
 3  * @desc   返利收费子类
 4  * @date 2021年09月28日 9:53
 5  */
 6 public class CashReturn extends CashSuper {
 7 
 8     private double moneyConditation = 0.0;  //返利条件
 9     private double moneyReturn = 0.0d;      //返利值
10 
11     public CashReturn(double moneyConditation, double moneyReturn) {
12         this.moneyConditation = moneyConditation;
13         this.moneyReturn = moneyReturn;
14     }
15 
16     @Override
17     public double acceptCash(double money) {
18         double result = money;
19         if(money >= moneyConditation){
20             result = money - moneyReturn;
21         }
22         return result;
23     }
24 }

 

 

(6)测试类

 1 /**
 2  * @author it-小林
 3  * @desc   客户端
 4  * @date 2021年09月28日 9:58
 5  */
 6 public class Client {
 7     public static void main(String[] args) {
 8         CashContext context = null;
 9 
10         Scanner scanner = new Scanner(System.in);
11         System.out.println("请输入打折方式(1/2/3):");
12         int in = scanner.nextInt();
13         String type = "";
14 
15         switch (in) {
16             case 1:
17                 context = new CashContext(new CashNormal());
18                 type += "正常收费";
19                 break;
20             case 2:
21                 context = new CashContext(new CashReturn(300, 200));
22                 type += "满300返100";
23                 break;
24             case 3:
25                 context = new CashContext(new CashRebate(0.8));
26                 type += "打8折";
27                 break;
28             default:
29                 System.out.println("请输入1/2/3");
30                 break;
31         }
32 
33         double totalPrices = 0;
34         System.out.print("请输入单价:");
35         double price = scanner.nextDouble();
36         System.out.print("请输入数量:");
37         double num = scanner.nextDouble();
38         totalPrices = context.getResult(price * num);
39         System.out.println("单价:" + price + ",数量:" + num + ",类型:" + type + ",合计:" + totalPrices);
40     }
41 }

 

运行结果

                                                            

 

                                                            

 

                                                            

 

posted @ 2021-09-28 11:24  it-小林  阅读(63)  评论(0编辑  收藏  举报