策略模式使用
概述
Java中的策略模式(Strategy Pattern)是一种行为型设计模式,它定义了一系列的算法,并将每一种算法封装起来,使它们可以相互替换。此模式让算法的变化独立于使用算法的客户。策略模式让算法的变化不会影响到使用算法的客户
策略模式组成及实现步骤
组成
- 策略接口(Strategy Interface) :定义所有支持的算法的公共接口。Context使用这个接口来调用某ConcreteStrategy定义的算法。
- 具体策略类(Concrete Strategies) :实现了Strategy接口的类。
- 上下文类(Context) :接受客户的请求并使用某个具体策略类来执行这个请求。维护对策略对象的引用,并可以在运行时动态地改变这个引用
实现步骤
- 定义策略接口:首先定义一个接口,这个接口中声明了算法或行为的方法。
- 实现具体策略:然后为每个算法实现一个类,这些类实现了上面定义的接口。
- 定义上下文类:该类用于接收客户端的请求,随后将请求委托给一个或多个策略对象,由策略对象来执行具体的算法。上下文类会维护对策略对象的引用,并可以在运行时根据需要切换策略对象
使用实例
本处以实现对某个接口参数处理的案例示例
1.定义策略类
public interface SiInterfaceDataStrategy {
String siInterfaceDataProcessing(String interfaceParams,String isPrintOperation);
}
2.定义策略实现类
/**
* @ClassName RosterOfActiveEmployeesPrintStrategy
* @Description 在职职工数据处理
* @Author avgrado
* @Date 2024-09-03 15:49
*/
@Component("activeEmployees")
@Slf4j
public class activeEmployeesInterfaceDataStrategy implements SiInterfaceDataStrategy {
@Resource
private RemoteInvoke remoteInvoke;
//此处需要加上无参构造方法,否则在使用的时候会报找不到方法的错误
public activeEmployeesInterfaceDataStrategy(){
}
@Override
public String siInterfaceDataProcessing(String params,String isPrintOperation) {
//此处是接口调用获取数据
String siInterfaceData = remoteInvoke.getData(params)
JSONObject jsonObject = JSONUtil.parseObj(siInterfaceData);
//如果是打印的操作,则组装打印所需的数据
if("1".equals(isPrintOperation)){
JSONArray array = jsonObject.getJSONArray("data");
JSONObject printObj = new JSONObject();
printObj.put("unitId",array.getJSONObject(0).getStr("unitId"));
printObj.put("unitName",array.getJSONObject(0).getStr("unitName"));
printObj.put("printTime",new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
printObj.put("list",jsonObject.getJSONArray("data"));
siInterfaceData = printObj.toString();
}
return siInterfaceData;
}
}
- 定义上下文
/**
* @ClassName SiInterfaceDataContext
* @Description 打印策略类的上下文
* @Author avgrado
* @Date 2024-09-03 16:05
*/
@Component
public class SiInterfaceDataContext {
private SiInterfaceDataStrategy siInterfaceDataStrategy;
// 告诉Spring通过构造函数注入siInterfaceDataStrategy类型的Bean
@Autowired
public SiInterfaceDataContext(SiInterfaceDataStrategy siInterfaceDataStrategy){
this.siInterfaceDataStrategy = siInterfaceDataStrategy;
}
public void setSiInterfaceDataStrategy(SiInterfaceDataStrategy siInterfaceDataStrategy){
this.siInterfaceDataStrategy = siInterfaceDataStrategy;
}
public String siInterfaceDataProcessing(String interfaceParams,String isPrintOperation){
return siInterfaceDataStrategy.siInterfaceDataProcessing(interfaceParams,isPrintOperation);
}
}
4.接口中的策略使用
//此处注入的策略map,后面可以通过策略名称取获取对应的实例
@Autowired
private Map<String, SiInterfaceDataStrategy> strategiesMap;
public String getData(String interfaceParams,isPrintOperation,stragegName){
/*
省略上面的业务代码
*/
SiInterfaceDataContext context = new SiInterfaceDataContext(strategiesMap.get(stragegName));
String data = context.siInterfaceDataProcessing(interfaceParams,isPrintOperation);
return data;
}
出现问题的地方:
要求实现根据传入的策略名称进行去找到具体的策略类调用: 想去通过反射的方式获取实现类,如下代码所示:但是忽略了使用反射获取到的策略实例并不是被spring管理的bean,会直接导致在策略类中注入的bean对象是null。接口调用失败,所以如果需要调整为第三步所示,在策略实现类上加上名称交给spring管理,然后通过注入的策略map,通过策略名去获取到策略实例
public String getData(String interfaceParams,isPrintOperation,stragegName){
//通过全限定名去获取class
Class<?> strategyClass = Class.forName(SiConstant.STRATEGY_CLASS_PATH+stragegName);
String name = strategyClass.getName();
log.info("获取到的名称是:{}",name);
strategyClass.getDeclaredConstructor().newInstance();
SiInterfaceDataContext context = new SiInterfaceDataContext(strategyClass.getDeclaredConstructor().newInstance());
String data = context.siInterfaceDataProcessing(interfaceParams,isPrintOperation);
}