策略(Strategy)模式:指定义一组算法,并将每个算法封装起来,运行时,可以灵活选择其中的某个算法

    优点:

    1. 策略模式可以有效避免多重if语句
    2. 策略模式可以提供相同行为的不同实现

    缺点:

    1. 调用方必须了解不同策略算法的区别,以便于在需要时调用
    2. 容易造成过多策略类,维护难度提高

    策略模式在Java标准库有着广泛的使用,以排序为例,可以看看通过Array.sort()方法实现忽略大小写排序

    1. public static void main(String[] args) {
    2. String[] arr = {"c","C","Z","a"};
    3. Arrays.sort(arr,String::compareToIgnoreCase);
    4. System.out.println(Arrays.toString(arr)); // [a, c, C, Z]
    5. }

    如果想要倒序排序则可以修改为:Arrays._sort_(arr,(s1,s2)-> s1.compareTo(s2)),如果想要忽悠大小写排序则可以使用:Arrays.sort(arr,String::compareToIgnoreCase);而这两种算法,即是策略

    上面的示例中使用到了策略模式,不难看出,策略模式的特点是:它的流程是确定的,但是某些算法依赖调用方传入的策略,不同的策略,实现了不同的结果,从而增强了系统的灵活性

    示例:
    一个完整的策略模式,要定义策略以及使用策略的上下文。以购物车结算为例,假设网站有普通用户,vip会员和超级vip会员,不同的用户享受的折扣不相同。
    �首先定义一个打折策略接口

    1. // 折扣策略接口
    2. interface DiscountStrategy{
    3. // 计算折扣
    4. BigDecimal getDiscount(BigDecimal total);
    5. }

    同时有各种策略的实现

    1. // 普通用户策略
    2. static class GeneralUser implements DiscountStrategy{
    3. @Override
    4. public BigDecimal getDiscount(BigDecimal total) {
    5. // 普通用户不享受折扣
    6. return total;
    7. }
    8. }
    9. // vip用户策略
    10. static class VipUser implements DiscountStrategy{
    11. @Override
    12. public BigDecimal getDiscount(BigDecimal total) {
    13. // vip用户享受8折优惠
    14. return total.multiply(new BigDecimal("0.2")).setScale(2, RoundingMode.DOWN);
    15. }
    16. }
    17. // 超级vip用户策略
    18. static class SuperVipUser implements DiscountStrategy{
    19. @Override
    20. public BigDecimal getDiscount(BigDecimal total) {
    21. // 超级vip用户享受6折优惠
    22. return total.multiply(new BigDecimal("0.4")).setScale(2, RoundingMode.DOWN);
    23. }
    24. }

    然后,需要一个可以使用策略的地方

    1. // 应用策略
    2. static class DiscountContext{
    3. // 默认策略为普通用户类型
    4. private DiscountStrategy strategy = new GeneralUser();
    5. // 可以设置用户类型
    6. public void setStrategy(DiscountStrategy strategy) {
    7. this.strategy = strategy;
    8. }
    9. // 计算折扣
    10. public BigDecimal calculatePrice(BigDecimal total){
    11. return total.subtract(this.strategy.getDiscount(total)).setScale(2,RoundingMode.CEILING);
    12. }
    13. }

    测试

    1. public static void main(String[] args) {
    2. DiscountContext context = new DiscountContext();
    3. // 普通用户无折扣
    4. BigDecimal price1 = context.calculatePrice(BigDecimal.valueOf(100));
    5. System.out.println(price1); // 100
    6. // vip用户8折优惠
    7. context.setStrategy(new VipUser());
    8. BigDecimal price2 = context.calculatePrice(BigDecimal.valueOf(100));
    9. System.out.println(price2); // 80
    10. // 超级VIP6折优惠
    11. context.setStrategy(new SuperVipUser());
    12. BigDecimal price3 = context.calculatePrice(BigDecimal.valueOf(100));
    13. System.out.println(price3); // 60
    14. }