网站被墙什么意思,用网站,青岛建站公司流程,博采网络科技有限公司策略类Spring框架下开发实例
先列出策略模式下需要那些类: 策略接口 (Strategy)#xff0c;定义所有策略类必须遵循的行为。 具体策略类#xff08;如 ConcreteStrategyA、ConcreteStrategyB#xff09;#xff0c;实现不同的算法或行为。 上下文类 (Context)#xff0c;…策略类Spring框架下开发实例
先列出策略模式下需要那些类: 策略接口 (Strategy)定义所有策略类必须遵循的行为。 具体策略类如 ConcreteStrategyA、ConcreteStrategyB实现不同的算法或行为。 上下文类 (Context)持有策略实例并根据条件动态选择和创建策略。 辅助类和注解作为工具辅助构建类工厂可忽略为策略模式的实现提供额外的功能或配置。 具体实现
定义策略接口 采用策略模式的情况一般是封装多重if-else/switch下的不同处理逻辑这些逻辑可以抽象为一个行为(比如封装参数做前置校验等)将这个行为定义为接口方法 /*** 策略接口*/
public interface ProductTypeHandler {//本例中根据不同产品类型执行不同的返回参数封装逻辑void assemble(ResponseBO resBO);
}定义策略类及其处理逻辑 将上文提到的多重if-else/switch中不同情况及其处理逻辑抽象成具体策略类和其内部方法执行逻辑 /*** 记录器参数处理类*/
Component
//注解使用见3
ProductTypeAssembleTag(TAG EnumProductType.PROCESS_RECORDER)
public class RecorderHandler implements ProductTypeHandler {Autowiredprivate RecorderService service;Overridepublic void assemble(ResponseBO resBO) {//记录器的处理逻辑int bindDeviceNums service.getNumByUserId(ContextUtil.getUserId());resBO.setValue(bindDeviceNums);}
}Component
ProductTypeAssembleTag(TAG EnumProductType.COMMANDER)
//继承见4
public class CommanderHandler extends CommonHandler implements ProductTypeHandler {Overridepublic void assemble(ResponseBO resBO) {//控制器的处理逻辑...}
}这里用到的注解和继承可以先忽视34中会做解释
Context上下文类 这个类的核心就是存储map所有的策略类然后提供getHandler()方法供外界匹配获取对应策略类执行相关逻辑 那么这个map是如何存储的呢?我在实践中遇到是通过MapTypeEnumHandler也就是定义枚举类作为键存储其对应枚举类 此处有一个可拓展的点就是这个map是如何封装的我遇到的有这么两种: 在Context中将所有策略类定义为属性然后Resourse注入通过注解的方式进行解耦 第一种自动注入switch的方式
Component
public class ProductTypeHandlerContext {Resourceprivate CommonHandler commonHandler;ResourceprivateRecorderHandler recorderHandler;//...其他策略类public ProductTypeHandler getHandler(EnumProductType emumType) {ProductTypeHandler handler null;switch (EnumProductType) {case COMMANDER:handler commonHandler;break;case RECORDER:handler recorderHandler;break;default:throw new BizException(未匹配到目标类型);break;}return handler;}
}
可以看到第一种方案比较轻量级下面来着重举例看看第二种情况:
Component
public class HandlerContext{private static final MapEnumProductType ProductTypeHandler handlerMap new HashMap();Autowiredprivate HandlerContext(ListProductTypeHandler handlers) {handlers.forEach(processor - {//这一段是通过反射获取到策略类long count new ArrayList(Arrays.asList(processor.getClass().getInterfaces())).stream().filter(m - m.getName().equals(org.springframework.aop.framework.Advised)).count();try {Class? ifaceClass (Class) (count 0 ? processor.getClass().getMethod(getTargetClass).invoke(processor) : processor.getClass());this.handlerMap.put(ifaceClass.getAnnotation(ProductTypeAssembleTag.class).TAG() processor);} catch (Exception e) {log.error(HandlerContext初始化失败e);throw new BizException(HandlerContext初始化失败);}});}public ProductTypeHandler getHandler(EnumProductType emumType) {return handlerMap.get(emumType);}
}可以看到Context主要分为三部分:
map构造函数–初始化mapgetHandler()
这里的重点在2中的HandlerContext()构造方法通过Autowired注解Spring会将所有继承了策略接口ProductTypeHandler的策略类注入为列表作为参数那么在方法内部对列表中的策略类依次进行map.put就可以了
那如何将策略类对应到其所属的EnumType上呢?这里通过自定义一个注解为其添加一个名为Tag的EnumType属性在每个策略类上面加上这个注解就大功告成了这也是上面的策略类的注解来源
/*** 注解*/
Target(ElementType.TYPE)
Retention(RetentionPolicy.RUNTIME)
public interface ProductTypeAssembleTag {EnumsLogin.EnumProductType TAG();
}
至于HandlerContext()中的try中所涉及的逻辑是检查当前的 processor 类是否是一个 Spring AOP 代理类:
org.springframework.aop.framework.Advised接口是 Spring AOP 代理类的标志。如果 count 0说明 processor 是一个 AOP 代理类。
如果 processor 是 AOP 代理类则调用 processor.getClass().getMethod(getTargetClass).invoke(processor) 获取目标类的 Class 对象这样可以获取到代理类的实际目标类即被代理的类。如果 processor 不是代理类则直接使用 processor.getClass()。 getTargetClass() 方法是 AOP 代理类的一个方法它返回代理对象的实际目标类即未被代理的原始类。 进一步思考
如果策略类ab的执行逻辑是一样的那么要写重复的代码吗?
这时候就可以回归到最基础的继承上通过定义一个CommonHandler在其中写一次默认逻辑然后其他策略类进行继承这也是上面的策略类有继承的原因
public class CommonHandler {public void assemble(ResponseBO resBO) {log.info(默认处理--目前没有特殊处理逻辑);}
}至此一个通过注解和继承优化的策略类实现方案就得以使用在调用类通过注入HandlerContext调用getHandler(enumType).assemble就可以传入枚举类获取对应策略类执行对应逻辑
总结
针对Context中map的两种初始化方案
方案优点缺点自动注入switch- 简单直观易于理解和维护- 性能较好避免了反射开销- 扩展性差需要修改 switch 语句才能添加新策略- 高耦合修改策略类需要修改 Context 类注解解耦- 解耦性强符合开闭原则- 易于扩展不需要修改现有代码- 支持 AOP 代理- 性能开销较高使用了反射– 启动时的反射性能开销