行为模式-> 策略模式(Strategy)

53 阅读4分钟

行为模式-> 策略模式(Strategy)

什么是策略模式

策略模式是一种行为设计模式, 它定义了一系列算法,并将这些算法封装到一个类中,使得他们可以相互替换。这样,我们可以在改变某个对象使用的算法的情况下,选择一个合适的算法来处理特定的任务,主要解决多重if-else的判断逻辑

角色组成

环境类(Context): 环境类是策略模式的核心类,它持有一个策略对象的引用,并在需要时调用策略对象的方法。
抽象策略类(Strategy): 定义了策略方法,这些方法表示不同的策略行为。
具体策略类(Concrete Strategy): 抽象策略类的实现,它实现了抽象策略类中定义的策略方法,并提供了具体的算法实现。不同的具体策略类具有不同的实现算法,它们之间可以相互替换,使得环境类在运行时可以动态地改变策略。

优缺点

优点:

  • 算法可以自由切换。
  • 避免使用多重条件判断。
  • 扩展性良好

缺点:

  • 策略类会增多。
  • 所有策略类都需要对外暴露。
  • 判断逻辑在客户端,需求改变时,要更改客户端的程序。

应用场景

生活场景

  • 假如你需要前往机场。 你可以选择乘坐公共汽车、 预约出租车或骑自行车。 这些就是你的出行策略。 你可以根据预算或时间等因素来选择其中一种策略。

Java场景

  • Spring Security中的认证和授权策略: 在Spring Security中,可以使用不同的策略来定义认证和授权的行为,例如PasswordAuthentication(密码验证)、RememberMeAuthentication(记住我功能验证)、RoleBasedAuthorization(基于角色的授权)等。通过配置不同的策略,可以灵活地适应不同的安全需求。
  • Comparator接口: 在使用排序算法时,可以通过实现Comparator接口来定义不同的比较策略,从而可以根据需求对对象进行自定义排序。
  • 线程池(ThreadPoolExecutor): 在ThreadPoolExecutor中,可以通过设定不同的拒绝策略(RejectedExecutionHandler)来处理无法提交的新任务。拒绝策略可以根据系统的需求选择不同的处理方式,如抛出异常、丢弃任务等。

代码实现

下面以出行选择交通工具为例,解释一下策略模式。

TransportationContext - 出行选择类(Context)

/**
 * @author cris
 * @className TransportationContext
 * @description
 * 出行环境策略
 * 在初始化TransportationContext对象时,将所有策略实现类塞进Map中,
 * key为视频类型(Car、Plane、Train) value为对应的视频实现类
 * 通过getTransportationStrategy方法,根据transportationType从map中渠道对应的视频策略
 * 从而隐藏了策略的具体实现逻辑。这种方式可以遵循开闭原则,因为在新增视频类型时,只需要增加对应的实现类
 * @date 2024/06/30 10:57
 **/
@Component
public class TransportationContext {
    private static final Map<String, TransportationStrategy> transportMap = new HashMap<>();

    /**
     * 对象初始化时,将所有策略实现类加入到map中
     *
     * @param transportationStrategyList 出行方式列表
     */
    public TransportationContext(List<TransportationStrategy> transportationStrategyList) {
        transportationStrategyList.forEach(item -> transportMap.put(item.getTransportationType(), item));
    }

    /**
     * 根据vehicleType获取对应的策略实现
     * @param transportationType 出行类型
     * @return 出行策略
     */
    public TransportationStrategy getTransportStrategy(String transportationType) {
        TransportationStrategy transportationStrategy = transportMap.get(transportationType);
        if (ObjectUtils.isEmpty(transportationStrategy)) {
            throw new RuntimeException("vehicle inValid!");
        }
        return transportationStrategy;
    }
}

TransportationStrategy - 出行策略接口(Strategy)

/**
 * @author cris
 * @className TransportationStrategy
 * @description 策略行为接口
 * @date 2024/06/30 10:55
 **/
public interface TransportationStrategy {

    // 旅行
    String toTravel();

    // 获取交通工具
    String getTransportationType();
}

具体策略类(CarStrategy) 小汽车

/**
 * @author cris
 * @className CarStrategy
 * @description 具体策略类(Concrete Strategy):小汽车
 * @date 2024/06/30 11:02
 **/
@Component
public class CarStrategy implements TransportationStrategy {
    @Override
    public String toTravel() {
        return "去惠州旅游";
    }

    @Override
    public String getTransportationType() {
        return "Car";
    }
}

具体策略类(TrainStrategy) 小火车

/**
 * @author cris
 * @className TrainStrategy
 * @description 具体策略类(Concrete Strategy):火车
 * @date 2024/06/30 11:03
 **/
@Component
public class TrainStrategy implements TransportationStrategy {
    @Override
    public String toTravel() {
        return "去长沙旅游";
    }

    @Override
    public String getTransportationType() {
        return "Train";
    }
}

具体策略类(PlaneStrategy) 小飞机

/**
 * @author cris
 * @className PlaneStrategy
 * @description 具体策略类(Concrete Strategy):飞机
 * @date 2024/06/30 11:02
 **/
@Component
public class PlaneStrategy implements TransportationStrategy {
    @Override
    public String toTravel() {
        return "去北京旅游";
    }

    @Override
    public String getTransportationType() {
        return "Plane";
    }
}

TestStrategy 测试

/**
 * @author cris
 * @className TestStrategy
 * @description
 * @date 2024/06/30 11:13
 **/
@SpringBootTest
public class TestStrategy {

    @Autowired
    private TransportationContext transportationContext;

    @Test
    public void test() {
        TransportationStrategy ts1 = transportationContext.getTransportStrategy("Car");
        String ts_1 = ts1.toTravel();
        System.out.println("ts_1:" + ts_1);
        TransportationStrategy ts2 = transportationContext.getTransportStrategy("Train");
        String ts_2 = ts2.toTravel();
        System.out.println("ts_2:" + ts_2);
        TransportationStrategy ts3 = transportationContext.getTransportStrategy("Plane");
        String ts_3 = ts3.toTravel();
        System.out.println("ts_3:" + ts_3);
    }
}

结果

ts_1:去湛江旅游
ts_2:去长沙旅游
ts_3:去北京旅游

总结