策略模式使用

175 阅读3分钟

策略模式使用

概述

Java中的策略模式(Strategy Pattern)是一种行为型设计模式,它定义了一系列的算法,并将每一种算法封装起来,使它们可以相互替换。此模式让算法的变化独立于使用算法的客户。策略模式让算法的变化不会影响到使用算法的客户

策略模式组成及实现步骤

组成

  1. 策略接口(Strategy Interface) :定义所有支持的算法的公共接口。Context使用这个接口来调用某ConcreteStrategy定义的算法。
  2. 具体策略类(Concrete Strategies) :实现了Strategy接口的类。
  3. 上下文类(Context) :接受客户的请求并使用某个具体策略类来执行这个请求。维护对策略对象的引用,并可以在运行时动态地改变这个引用

实现步骤

  1. 定义策略接口:首先定义一个接口,这个接口中声明了算法或行为的方法。
  2. 实现具体策略:然后为每个算法实现一个类,这些类实现了上面定义的接口。
  3. 定义上下文类:该类用于接收客户端的请求,随后将请求委托给一个或多个策略对象,由策略对象来执行具体的算法。上下文类会维护对策略对象的引用,并可以在运行时根据需要切换策略对象

使用实例

本处以实现对某个接口参数处理的案例示例

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;
    }
}
  1. 定义上下文

/**
 * @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);
}