设计模式之策略模式

  • 策略模式(Strategy Pattern)

    • 定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换
  • 应用场景

    • 老王计划外出旅游,选择骑自行车、坐汽车、飞机等,每一种旅行方式都是一个策略
    • Java AWT中的LayoutManager,即布局管理器
    • 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么可以使用策略模式
    • 不希望暴露复杂的、与算法有关的数据结构,那么可以使用策略模式来封装算法
  • 角色

    • Context上下文:屏蔽高层模块对策略、算法的直接访问,封装可能存在的变化

    • Strategy策略角色:抽象策略角色,是对策略、算法家族的抽象,定义每个策略或算法必须具有的方法和属性

    • ConcreteStrategy具体策略角色:用于实现抽象策略中的操作,即实现具体的算法
      在这里插入图片描述

  • 代码示例:电商优惠活动举例

    /**
     * 订单
     */
    class ProductOrder {
        private double oldPrice;
        private int userId;
        private int productId;
    
        public ProductOrder(double oldPrice, int userId, int productId) {
            this.oldPrice = oldPrice;
            this.userId = userId;
            this.productId = productId;
        }
    
        public double getOldPrice() {
            return oldPrice;
        }
    
        public void setOldPrice(double oldPrice) {
            this.oldPrice = oldPrice;
        }
    
        public int getUserId() {
            return userId;
        }
    
        public void setUserId(int userId) {
            this.userId = userId;
        }
    
        public int getProductId() {
            return productId;
        }
    
        public void setProductId(int productId) {
            this.productId = productId;
        }
    }
    
    /**
     * 抽象策略角色
     */
    abstract class Strategy {
        public abstract double computePrice(ProductOrder productOrder);
    }
    
    /**
     * 上下文
     */
    class PromotionContext {
        private Strategy strategy;
    
        public PromotionContext(Strategy strategy) {
            this.strategy = strategy;
        }
    
        public double executeStrategy(ProductOrder productOrder) {
            return strategy.computePrice(productOrder);
        }
    }
    
    /**
     * 不打折策略
     */
    class NormalActivity extends Strategy {
        @Override
        public double computePrice(ProductOrder productOrder) {
            return productOrder.getOldPrice();
        }
    }
    
    /**
     * 折扣策略
     */
    class DiscountActivity extends Strategy {
    
        // 具体的折扣
        private double rate;
    
        public DiscountActivity(double rate) {
            this.rate = rate;
        }
    
        @Override
        public double computePrice(ProductOrder productOrder) {
            return productOrder.getOldPrice() * rate;
        }
    }
    
    public class Main {
        public static void main(String[] args) {
            ProductOrder productOrder = new ProductOrder(100, 1, 1);
    
            PromotionContext context = new PromotionContext(new NormalActivity());
            double price = context.executeStrategy(productOrder);
            System.out.println("不打折扣价格:" + price);
    
            PromotionContext context1 = new PromotionContext(new DiscountActivity(0.8));
            double price1 = context1.executeStrategy(productOrder);
            System.out.println("打8折:" + price1);
        }
    }
    
  • 优点

    • 满足开闭原则,当增加新的具体策略时,不需要修改上下文类的代码,上下文就可以引用新的具体策略的实例
    • 避免使用多重条件判断,如果不用策略模式可能会使用多重条件语句不利于维护,和工厂模式的搭配使用可以很好地消除代码if-else的多层嵌套(工厂模式主要是根据参数,获取不同的策略)
  • 缺点

    • 策略类数量会增多,每个策略都是一个类,复用的可能性很小
    • 对外暴露了类所有的行为和算法,行为过多导致策略类膨胀
  • JDK源码的应用

    • Comparator接口常用的compare()方法,就是一个策略模式的应用,把Comparator作为参数使用生成不同的排序策略

      import java.util.ArrayList;
      import java.util.Collections;
      import java.util.Comparator;
      
      class Student {
          private String name;
          private int age;
      
          public Student(String name, int age) {
              this.name = name;
              this.age = age;
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          public int getAge() {
              return age;
          }
      
          public void setAge(int age) {
              this.age = age;
          }
      
          @Override
          public String toString() {
              return "Student{" +
                      "name='" + name + '\'' +
                      ", age=" + age +
                      '}';
          }
      }
      
      public class Main {
          public static void main(String[] args) {
              Student zhangsan = new Student("张三", 18);
              Student lisi = new Student("李四", 55);
              ArrayList<Student> list = new ArrayList<>();
              list.add(zhangsan);
              list.add(lisi);
      
              Collections.sort(list, new Comparator<Student>() {
                  @Override
                  public int compare(Student o1, Student o2) {
                      // 年龄升序
                      //return o1.getAge()-o2.getAge();
      
                      // 年龄降序
                      return o2.getAge() - o1.getAge();
                  }
              });
      
              System.out.println(list);
          }
      }
      
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Gen邓艮艮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值