简介
策略模式(Strategy Pattern)又叫作政策模式(Policy Pattern),它将定义的算法家族分别封装起来,让它们之间可以互相替换,从而让算法的变化不会影响到使用算法的用户,属于行为型设计模式。
通用模板
-
创建抽象策略角色:规定策略或算法的行为。
// 策略接口 public interface IStrategy {void algorithm(); }
-
创建具体策略角色:具体的策略或算法实现。
// 具体策略类A public class ConcreteStrategyA implements IStrategy{@Overridepublic void algorithm() {System.out.println("ConcreteStrategyA");} }
// 具体策略类B public class ConcreteStrategyB implements IStrategy {@Overridepublic void algorithm() {System.out.println("ConcreteStrategyB");} }
-
上下文角色:用来操作策略的上下文环境,屏蔽高层模块(客户端)对策略、算法的直接访问,封装可能存在的变化。
// 操作策略的上下文 public class Context {private IStrategy strategy;public Context(IStrategy strategy) {this.strategy = strategy;}public void algorithm() {this.strategy.algorithm();} }
模板测试
-
测试代码
public class Client {public static void main(String[] args) {// 选择一个具体策略IStrategy strategy = new ConcreteStrategyA();// 创建一个上下文环境Context context = new Context(strategy);// 客户端直接让上下文角色执行算法context.algorithm();} }
-
结果
ConcreteStrategyA
应用场景
策略模式在生活场景中的应用非常多。比如,一个人的纳税比率与他的工资有关,不同的工资水平对应不同的税率。再比如,在互联网移动支付的大背景下,我们每次下单后付款前,都需要选择支付方式。
策略模式可以解决在有多种相似算法的情况下使用if…else或switch…case所带来的复杂性和臃肿性问题。在日常业务开发中,策略模式适用于以下应用场景。
(1)针对同一类型问题,有多种处理方式,每一种都能独立解决问题。
(2)需要自由切换算法的场景。
(3)需要屏蔽算法规则的场景。
优点
(1)策略模式符合开闭原则。
(2)避免使用多重条件转移语句,如if…else语句、switch…case语句
(3)使用策略模式可以提高算法的保密性和安全性。
缺点
(1)客户端必须知道所有的策略,并且自行决定使用哪一个策略类。
(2)代码中会产生非常多策略类,增加维护难度。
“生搬硬套”实战
场景描述
假设你是一名餐厅经理,餐厅提供多种优惠活动来吸引顾客。优惠活动包括打折、满减、买一送一等。每种优惠活动都有不同的计算方式,但餐厅的收银系统需要能够灵活地应用这些优惠活动。
代码开发
-
创建抽象策略角色(这里指打折策略接口)
// 打折策略接口 public interface IDiscountStrategy {double applyDiscount(double originalPrice); }
-
创建具体策略角色(这里指百分比打折策略、固定金额减免策略、买一送一策略)
// 根据折扣百分比计算最终价格 public class PercentageDiscount implements IDiscountStrategy {private double discountPercentage;public PercentageDiscount(double discountPercentage) {this.discountPercentage = discountPercentage;}@Overridepublic double applyDiscount(double originalPrice) {return originalPrice * (1 - discountPercentage / 100);} }
// 根据固定金额减免计算最终价格 public class FixedAmountDiscount implements IDiscountStrategy {private double discountAmount;public FixedAmountDiscount(double discountAmount) {this.discountAmount = discountAmount;}@Overridepublic double applyDiscount(double originalPrice) {return Math.max(originalPrice - discountAmount, 0); // 确保折扣后价格不低于0} }
// 买一送一策略,计算最终价格为原价的一半 public class BuyOneGetOneFree implements IDiscountStrategy {@Overridepublic double applyDiscount(double originalPrice) {return originalPrice / 2; // 买一送一,相当于半价} }
-
创建上下文(这里就是收银系统)
// 用来操作策略的上下文,这里就是收银系统 public class Cashier {private IDiscountStrategy strategy;public Cashier(IDiscountStrategy strategy) {this.strategy = strategy;}public double calculateFinalPrice(double originalPrice) {return strategy.applyDiscount(originalPrice);} }
至此,我们就通过“生搬硬套”策略模式的模板设计出一套上下文可以灵活选择不同策略算法的系统,接下来我们进行测试:
- 测试代码
public class Client {public static void main(String[] args) {// 折扣百分比策略IDiscountStrategy percentageDiscount = new PercentageDiscount(10);Cashier cashierWithPercentageDiscount = new Cashier(percentageDiscount);double finalPriceWithPercentage = cashierWithPercentageDiscount.calculateFinalPrice(100);System.out.println("Final price with percentage discount: " + finalPriceWithPercentage);// 固定金额减免策略IDiscountStrategy fixedAmountDiscount = new FixedAmountDiscount(20);Cashier cashierWithFixedAmountDiscount = new Cashier(fixedAmountDiscount);double finalPriceWithFixedAmount = cashierWithFixedAmountDiscount.calculateFinalPrice(100);System.out.println("Final price with fixed amount discount: " + finalPriceWithFixedAmount);// 买一送一策略IDiscountStrategy buyOneGetOneFree = new BuyOneGetOneFree();Cashier cashierWithBuyOneGetOneFree = new Cashier(buyOneGetOneFree);double finalPriceWithBuyOneGetOneFree = cashierWithBuyOneGetOneFree.calculateFinalPrice(100);System.out.println("Final price with buy one get one free: " + finalPriceWithBuyOneGetOneFree);} }
- 结果
Final price with percentage discount: 90.0 Final price with fixed amount discount: 80.0 Final price with buy one get one free: 50.0
总结
策略是指,定义一组算法,并把其封装到一个对象中。然后在运行时,可以灵活的使用其中的一个算法。这种模式非常适合那些需要根据不同情况选择不同行为的场景。