行为模式-> 策略模式(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:去北京旅游