Java 策略模式的演进:从基础实现到高效优化
一、引言
在软件开发中,策略模式是一种常用的设计模式,它允许在运行时选择算法的行为。本文将详细介绍策略模式在 Java 中的实现,从最基础的版本逐步演进到最终的高效优化版本,旨在解决策略选择、排序以及避免代码中大量 if-else 语句等问题。
二 第一版 基础策略模式实现
在策略模式的第一版中,我们按照传统的方式实现,即定义接口、实现接口、将实现类注入容器,然后通过循环调用不同的策略。
接口定义
接口定义了策略类需要实现的方法,为后续的策略实现提供了统一的规范。

主程序
主程序负责调用不同的策略,通过循环遍历策略列表,找到合适的策略并执行。
三 第二版 新增兜底策略及排序问题解决
随着业务的发展,我们需要新增兜底策略,但为了防止兜底策略截断后续的策略实现,我们需要对策略类进行排序。
问题分析
兜底策略可能会在不恰当的时候被执行,从而影响其他策略的正常调用。
解决方案
我们可以给其他策略类添加 @Order 注解,这个注解可以控制 Bean 的生成顺序,从而保证策略类按照我们期望的顺序执行。

所以 我们可以给其他策略类 加 order 注解 这个注解可以控制 bean 的生成顺序
四 第三版:将策略选择交给主流程
为了更好地管理策略的选择,我们将策略的选择逻辑从具体的策略类中分离出来,交给主流程处理。我们使用一个枚举来表示不同的用户类型,并在主流程中编写一个方法来返回对应的策略。
枚举定义
public enum userType {
NORMAL,
SMALL,
BIG,
SUPER,
PERSONAL
}
接口定义
public interface CustomerService {
userType getUserType();
// 校验
String findCustomer();
}
策略实现类
@Component
@Order(1)
public class SuperCustomerService implements CustomerService {
@Override
public userType getUserType() {
return userType.SUPER;
}
@Override
public String findCustomer() {
return null;
}
}
控制器类
@RestController
public class stratgeyController {
@Autowired
List<CustomerService> customerServiceList;
@RequestMapping("customer/{recharge}")
public String customer(@PathVariable("recharge") int recharge){
for (CustomerService customerService : customerServiceList) {
if (customerService.getUserType().equals(analysisUserType(recharge))) {
return customerService.findCustomer();
}
}
throw new IllegalArgumentException("找不到客服");
}
private userType analysisUserType(int recharge){
if(recharge>0 && recharge<=100){
return userType.NORMAL;
}
if(recharge>100 && recharge<=1000){
return userType.SMALL;
}
if(recharge>1000 && recharge<=10000){
return userType.BIG;
}
if(recharge>10000 && recharge<=100000){
return userType.SUPER;
}
if(recharge>100000 && recharge<=1000000){
return userType.PERSONAL;
}
return null;
}
}
缺点分析
缺点是 主方法依旧存在了大量的 if-else
五、第四版:在枚举中做循环
为了避免主方法中大量的 if-else 语句,我们在枚举中实现一个方法,该方法接收充值金额参数 recharge,通过遍历枚举的所有成员,对每个成员使用 Lambda 表达式判断其是否满足充值金额条件,若满足则返回对应的枚举值。
枚举优化
public enum UserType {
NORMAL(recharge-> recharge>0 && recharge<=100),
SMALL(recharge-> recharge>100 && recharge<=1000),
BIG(recharge-> recharge>1000 && recharge<=10000),
SUPER(recharge-> recharge>10000 && recharge<=100000),
PERSONAL(recharge-> recharge>100000 && recharge<=1000000);
private final IntPredicate support;
UserType(IntPredicate support){
this.support=support;
}
public static UserType typeOf(int recharge){
for (UserType value : UserType.values()) {
if(value.support.test(recharge)){
return value;
}
}
return null;
}
}
在枚举中实现一个方法,该方法接收充值金额参数 recharge,通过遍历枚举的所有成员,对每个成员使用 Lambda 表达式判断其是否满足充值金额条件(如 recharge 落在该成员对应的金额区间内),若满足则返回对应的枚举值。
后续就可以移除 analysisUserType 在主流程直接根据 recharge 返回枚举 然后遍历策略类 判断策略类的枚举类型是否和参数对应的枚举类型相等就可以

新问题分析
现在的问题是 如果我的策略类有一百个 那我每次不都要遍历一百次了么???
六、第五版:使用 Map 替换 List
为了提高策略选择的效率,我们使用一个 Map 来存储枚举以及枚举对应的策略类。使用构造注入法,在项目启动时遍历一次策略类列表,将 Map 进行赋值,后续可以直接通过枚举从 Map 中获取对应的策略类。
@RestController
public class stratgeyController {
@Autowired
DefaultCustomerService defaultCustomerService;
Map<UserType,CustomerService> map;
@RequestMapping("customer/{recharge}")
public String customer(@PathVariable("recharge") int recharge){
// 通过充值金额判断用户类型
UserType userType = UserType.typeOf(recharge);
CustomerService customerService = map.getOrDefault(userType,defaultCustomerService);
return customerService.findCustomer();
}
@Autowired
public void setCustomerMap(List<CustomerService> customerServiceList){
map= customerServiceList
.stream()
.filter(customerService -> customerService.getUserType()!=null)
.collect(Collectors.toMap( CustomerService::getUserType, Function.identity()));
}
这里主要是 用一个 map 来存储枚举 以及枚举对应的策略类
使用构造注入法 这样只要项目启动的时候 遍历一次就行 然后就可以把 map 进行赋值
map 中 key 就是枚举 value 就是对应的策略类.
七、最终版:使用自定义注解优化接口
因为我们接口中 还是有一个方法 来获取策略类对应的枚举 如果只想要策略接口足够干净 只留一个处理方法 那么可以用到自定义注解 给每个策略实现类的注解 value 换成对应的枚举 这样在填充 map 时候 获取特定注解的 value 就可以了 这样可以让策略接口只需要有处理方法 就行
自定义注解定义
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface SupportUserType {
UserType value();
}
策略实现类
@Component
@SupportUserType(UserType.BIG)
public class BigCustomerSercice implements CustomerService {
@Override
public String findCustomer() {
return "大r客服";
}
}
控制器类
@RestController
public class stratgeyController {
@Autowired
DefaultCustomerService defaultCustomerService;
Map<UserType,CustomerService> map;
@RequestMapping("customer/{recharge}")
public String customer(@PathVariable("recharge") int recharge){
// 通过充值金额判断用户类型
UserType userType = UserType.typeOf(recharge);
CustomerService customerService = map.getOrDefault(userType,defaultCustomerService);
return customerService.findCustomer();
}
@Autowired
public void setCustomerMap(List<CustomerService> customerServiceList){
map= customerServiceList
.stream()
.filter(customerService -> customerService.getClass().isAnnotationPresent(SupportUserType.class))
.collect(Collectors.toMap(this::getCustomerServiceUserTypeFunction, Function.identity()));
if(this.map.size()!=UserType.values().length){
throw new IllegalArgumentException("有策略类没有注入进来");
}
}
// 获取注解value
private UserType getCustomerServiceUserTypeFunction(CustomerService customerService) {
return customerService.getClass().getAnnotation(SupportUserType.class).value();
}
}
八、总结
通过不断地优化和改进,我们从基础的策略模式实现逐步演进到最终的高效优化版本。使用枚举、Map 和自定义注解等技术,解决了策略选择、排序以及代码可维护性等问题,提高了系统的性能和可扩展性。
更多推荐


所有评论(0)