策略模式
策略模式是对算法的包装,把使用算法的责任和算法本身分隔开,委派给不同的对象管理。策略模式通常把一系列的算法包装到一系列的策略类里面,作为一个抽象策略类的子类。比如我们去逛商场,商场现在正在搞活动,有打折的、有满减的、有返利的等等,其实不管商场如何进行促销,说到底都是一些算法,这些算法本身只是一种策略,并且这些算法是随时都可能互相替换的。
1. 何时使用
- 一个系统有许多类,而区分它们的只是他们直接的行为时
2. 方法
- 将这些算法封装成一个一个的类,任意的替换
3. 优点
- 算法可以自由切换
- 避免使用多重条件判断(如果不用策略模式我们可能会使用多重条件语句,不利于维护)
- 扩展性良好,增加一个策略只需实现接口即可
4. 缺点
- 策略类数量会增多,每个策略都是一个类,复用的可能性很小
- 所有的策略类都需要对外暴露
以商场促销为例使用策略模式实现商场促销算法。UML图如下:
1. CashContext类
首先声明一个CashSuper对象,通过构造方法,传入具体的收费策略,getResult()方法的功能为根据收费策略的不同获得计算结果。
public class CashContext { private CashSuper cashSuper; public CashContext(CashSuper cashSuper) { this.cashSuper = cashSuper; } public double getResult(double money) { return cashSuper.acceptCash(money); } }
2. CashSuper类
策略类,为抽象类,抽象出收费的方法供子类实现。
public abstract class CashSuper { public abstract double acceptCash(double money); }
3. 三类收费子类
public class CashNormal extends CashSuper { public double acceptCash(double money) { return money; } } public class CashRebate extends CashSuper { private double moneyRebate = 1; //折扣 public CashRebate(double moneyRebate) { this.moneyRebate = moneyRebate; } public double acceptCash(double money) { return money * moneyRebate; } } public class CashReturn extends CashSuper { private double moneyConditation = 0.0; //返利条件 private double moneyReturn = 0.0d; //返利值 public CashReturn(double moneyConditation, double moneyReturn) { this.moneyConditation = moneyConditation; this.moneyReturn = moneyReturn; } public double acceptCash(double money) { double result = money; if (money >= moneyConditation) { result = money - Math.floor(money / moneyConditation) * moneyReturn; } return result; } }
4. 测试类测试结果
public class Client { public static void main(String[] args) { CashContext cashContext = null; Scanner scanner = new Scanner(System.in); System.out.print("请输入打折方式(1/2/3):"); int in = scanner.nextInt(); String type = ""; switch (in) { case 1: cashContext = new CashContext(new CashNormal()); type += "正常收费"; break; case 2: cashContext = new CashContext(new CashReturn(300, 100)); type += "满300返100"; break; case 3: cashContext = new CashContext(new CashRebate(0.8)); type += "打8折"; break; default: System.out.println("请输入1/2/3"); break; } double totalPrices = 0; System.out.print("请输入单价:"); double price = scanner.nextDouble(); System.out.print("请输入数量:"); double num = scanner.nextDouble(); totalPrices = cashContext.getResult(price * num); System.out.println("单价:" + price + ",数量:" + num + ",类型:" + type + ",合计:" + totalPrices); scanner.close(); } }
以输入2例输出结果
总结
使用场景
- 多个类只有算法或行为上稍有不同的场景
- 算法需要自由切换的场景
- 需要屏蔽算法规则的场景
应用实例
- 出行方式,自行车、汽车等,每一种出行方式都是一个策略
- 商场促销方式,打折、满减等
- Java AWT中的LayoutManager,即布局管理器
注意事项
- 如果一个系统的策略多于四个,就需要考虑使用混合模式来解决策略类膨胀的问题