策略(Strategy)模式:指定义一组算法,并将每个算法封装起来,运行时,可以灵活选择其中的某个算法
优点:
- 策略模式可以有效避免多重if语句
- 策略模式可以提供相同行为的不同实现
缺点:
- 调用方必须了解不同策略算法的区别,以便于在需要时调用
- 容易造成过多策略类,维护难度提高
策略模式在Java标准库有着广泛的使用,以排序为例,可以看看通过Array.sort()方法实现忽略大小写排序
public static void main(String[] args) {String[] arr = {"c","C","Z","a"};Arrays.sort(arr,String::compareToIgnoreCase);System.out.println(Arrays.toString(arr)); // [a, c, C, Z]}
如果想要倒序排序则可以修改为:Arrays._sort_(arr,(s1,s2)-> s1.compareTo(s2)),如果想要忽悠大小写排序则可以使用:Arrays.sort(arr,String::compareToIgnoreCase);而这两种算法,即是策略
上面的示例中使用到了策略模式,不难看出,策略模式的特点是:它的流程是确定的,但是某些算法依赖调用方传入的策略,不同的策略,实现了不同的结果,从而增强了系统的灵活性
示例:
一个完整的策略模式,要定义策略以及使用策略的上下文。以购物车结算为例,假设网站有普通用户,vip会员和超级vip会员,不同的用户享受的折扣不相同。
�首先定义一个打折策略接口
// 折扣策略接口interface DiscountStrategy{// 计算折扣BigDecimal getDiscount(BigDecimal total);}
同时有各种策略的实现
// 普通用户策略static class GeneralUser implements DiscountStrategy{@Overridepublic BigDecimal getDiscount(BigDecimal total) {// 普通用户不享受折扣return total;}}// vip用户策略static class VipUser implements DiscountStrategy{@Overridepublic BigDecimal getDiscount(BigDecimal total) {// vip用户享受8折优惠return total.multiply(new BigDecimal("0.2")).setScale(2, RoundingMode.DOWN);}}// 超级vip用户策略static class SuperVipUser implements DiscountStrategy{@Overridepublic BigDecimal getDiscount(BigDecimal total) {// 超级vip用户享受6折优惠return total.multiply(new BigDecimal("0.4")).setScale(2, RoundingMode.DOWN);}}
然后,需要一个可以使用策略的地方
// 应用策略static class DiscountContext{// 默认策略为普通用户类型private DiscountStrategy strategy = new GeneralUser();// 可以设置用户类型public void setStrategy(DiscountStrategy strategy) {this.strategy = strategy;}// 计算折扣public BigDecimal calculatePrice(BigDecimal total){return total.subtract(this.strategy.getDiscount(total)).setScale(2,RoundingMode.CEILING);}}
测试
public static void main(String[] args) {DiscountContext context = new DiscountContext();// 普通用户无折扣BigDecimal price1 = context.calculatePrice(BigDecimal.valueOf(100));System.out.println(price1); // 100// vip用户8折优惠context.setStrategy(new VipUser());BigDecimal price2 = context.calculatePrice(BigDecimal.valueOf(100));System.out.println(price2); // 80// 超级VIP6折优惠context.setStrategy(new SuperVipUser());BigDecimal price3 = context.calculatePrice(BigDecimal.valueOf(100));System.out.println(price3); // 60}
