策略模式

策略模式用于解决判断分支过多的问题,使代码变得简洁和优雅,

策略模式在多种方式在项目中落地,下面举例说明通过指定不同类型的订单使用策略模式执行不同的业务逻辑

文章参考自公众号:石杉的架构笔记

一.项目结构

 二.各个类的说明

  1.自定义注解

  //通过注解中的value值来表示不同的分支,从而执行不同的业务逻辑

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface HandlerType { String value();
}

  2.处理器相关

    -抽象处理器-定义子处理器要实现的行为

public abstract class AbstractHandler {

    public  abstract String handle(OrderDTO dto);
}

    -子处理器1-实现抽相关处理器的行为1

@HandlerType(value = "1")
@Component
public class NomalHandler extends AbstractHandler{
@Override
public String handle(OrderDTO dto) {
return "normal";
}
}

    -子处理器2-实现抽相关处理器的行为2

@HandlerType(value = "2")
@Component
public class GroupHandler extends AbstractHandler{
@Override
public String handle(OrderDTO dto) {
return "group";
}
}

    -处理器上下文-根据不同条件映射到不同的处理器

public class HandleContext {

    private Map<String,Class> handlerMap;

    public HandleContext(Map<String,Class> handlerMap){
this.handlerMap=handlerMap;
} public AbstractHandler getInstance(String type){
Class<? extends AbstractHandler> aClass = handlerMap.get(type);
if (aClass==null) {
throw new IllegalArgumentException();
}
return SpringContextUtil.getBean(aClass);
}
}

  3.处理器加载类-用于加载处理器上下文到spring的bean容器中,同时初始化数据

@Component
@SuppressWarnings("unchecked")
public class HandlerProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
Map<String, Class> handlerMap = new HashMap<>();
//获取指定报下的所有类
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
MetadataReaderFactory metaReader = new CachingMetadataReaderFactory();
List<Class<?>> list = new ArrayList();
try {
Resource[] resources = resolver.getResources("classpath*:designstrategy/demo/config/handler/*.class"); ClassLoader loader = ClassLoader.getSystemClassLoader();
for (Resource resource : resources) {
MetadataReader reader = metaReader.getMetadataReader(resource);
String className = reader.getClassMetadata().getClassName();
Class<?> clazz = loader.loadClass(className);
HandlerType annotation = clazz.getAnnotation(HandlerType.class);
// System.out.println("格式化前:"+clazz); class designstrategy.demo.config.handler.AbstractHandler
System.err.println("格式化后:" + ClassUtils.getQualifiedName(clazz));
//获取所有接口
ClassUtils.getAllInterfaces(clazz);
//判断是一个类是不是抽象类
boolean anAbstract = Modifier.isAbstract(clazz.getModifiers());
// System.err.println("判断一个类是不是抽象类:" + anAbstract);如果不是抽象类,添加到集合
if (!anAbstract) {
list.add(clazz);
}
}
System.out.println("集合" + list);
//将类添加到Map中
for (Class<?> aClass : list) {
Annotation[] annotations = aClass.getAnnotations();
// 这里有个坑 Annotation annotation = aClass.getAnnotation(HandlerType.class);获取到的annotation为null
for (Annotation annotation : annotations) {
if (annotation instanceof HandlerType) {
String value = ((HandlerType) annotation).value();
handlerMap.put(value, aClass);
System.out.println(value);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
HandleContext handleContext = new HandleContext(handlerMap);
//将上下文添加到spring bean容器中
configurableListableBeanFactory.registerSingleton(HandleContext.class.getName(), handleContext);
}
}

  4.工具类-用于获取spring 容器中的bean

@Component
public class SpringContextUtil implements ApplicationContextAware { private static ApplicationContext applicationContext; @Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringContextUtil.applicationContext = applicationContext;
} //获取applicationContext
public static ApplicationContext getApplicationContext() {
return applicationContext;
} //通过name获取 Bean.
public static Object getBean(String name) {
return getApplicationContext().getBean(name);
} //通过class获取Bean.
public static <T> T getBean(Class<T> clazz) {
return getApplicationContext().getBean(clazz);
} //通过name,以及Clazz返回指定的Bean
public static <T> T getBean(String name, Class<T> clazz) {
return getApplicationContext().getBean(name, clazz);
} }

  5.controller层

@RestController
@RequestMapping("/order")
public class OrderController { @Autowired
private OrderService orderService; @RequestMapping("/handle")
public String handle(OrderDTO dto){
String str=orderService.handle(dto);
System.out.println(str);
return str;
}
}

  6.service层

@Service
public class OrderServiceImpl implements OrderService{ @Autowired
private HandleContext handleContext; @Override
public String handle(OrderDTO dto) {
AbstractHandler handler = handleContext.getInstance(dto.getType());
return handler.handle(dto);
}
}

  7.实体 

@Data
public class OrderDTO {
/** 订单类型 */
private String type;
}

三.测试

启动项目:使用postman分别测试以下两个接口

接口一:localhost:8080/order/hander?type=1

返回结果:normal

接口二localhost:8080/order/hander?type=2

返回结果:group

代码地址:https://github.com/AlenYang123456/design-strategy

  

【策略模式】策略模式结合Spring实战Demo的更多相关文章

  1. 【责任链模式】责任链模式结合Spring实战Demo

    备注: 责任链与策略模式有很多相似之处,如都是行为型设计模式,都能够处理代码中的if-else逻辑 主要区别在于: 策略模式 封装了算法,通过上下文对象去接受客户端的数据,根据数据类型执行不同的算法 ...

  2. 《设计模式面试小炒》策略和工厂模式替代业务场景中复杂的ifelse

    <设计模式面试小炒>策略和工厂模式替代业务场景中复杂的ifelse 我是肥哥,一名不专业的面试官! 我是囧囧,一名积极找工作的小菜鸟! 囧囧表示:小白面试最怕的就是面试官问的知识点太笼统, ...

  3. 3.js模式-策略模式

    1. 策略模式 策略模式定义一系列的算法,把它们封装起来,并且可以互相替换. var strategies = { isNonEmpty: function(value,errMsg){ if(val ...

  4. 模板模式与策略模式/template模式与strategy模式/行为型模式

    模板模式 模版模式,又被称为模版方法模式,它可以将工作流程进行封装,并且对外提供了个性化的控制,但主流程外界不能修改,也就是说,模版方法模式中,将工作的主体架构规定好,具体类可以根据自己的需要,各自去 ...

  5. 命令模式 & 策略模式 & 模板方法

    一.策略模式 策略模式:封装易变化的算法,可互相替换. GoF<设计模式>中说道:定义一系列算法,把它们一个个封装起来,并且使它们可以相互替换.该模式使得算法可独立于它们的客户变化. 比如 ...

  6. Java设计模式(七)策略模式 模板模式

    (十三)策略模式 策略图案限定了多个封装算法,该算法可以相互替换包.法的客户.借用还有一位大神的样例. interface ICalculator{ public int calculate(Stri ...

  7. Springboot中实现策略模式+工厂模式

    策略模式和工厂模式相信大家都比较熟悉,但是大家有没有在springboot中实现策略和工厂模式? 具体策略模式和工厂模式的UML我就不给出来了,使用这个这两个模式主要是防止程序中出现大量的IF ELS ...

  8. 工厂模式&策略模式。

    抽象.封装,具体事情做得越多,越容易犯错误.这每个做过具体工作的人都深有体会,相反,官做得越高,说出的话越抽象越笼统,犯错误可能性就越少.好象我们从编程序中也能悟出人生道理.(百度百科) 不断抽象封装 ...

  9. 简单工厂模式&策略模式-简介与区别

    不得不说,这两种模式真的很像. 相似点:都用到了面向对象的继承.多态.抽象,都拥有相似的结构. 不同点:工厂模式仅提供具体的实例对象,怎么使用这个对象是client的自由,策略模式client可以通过 ...

随机推荐

  1. Git:使用远程仓库

    远程仓库可使用Github.Gitee,或自建Gitlab.Gogs服务器,这里使用Github. 配置本地用户名和邮箱 # 配置本地用户的用户名邮箱(保存在用户.gitconfig文件) $ git ...

  2. redis使用ssh密钥远控靶机

      首先说明一下我们的实验目的,我们这个实验需要利用一种公有密码,将公有密钥写入要攻击的服务器的redis数据库,然后使用我们自己的私钥进行远控肉鸡的操作. 实验环境:centos7(靶机,版本无太大 ...

  3. 初探JavaScript原型链污染

    18年p师傅在知识星球出了一些代码审计题目,其中就有一道难度为hard的js题目(Thejs)为原型链污染攻击,而当时我因为太忙了(其实是太菜了,流下了没技术的泪水)并没有认真看过,后续在p师傅写出w ...

  4. jdk8的安装与环境搭建

    jdk8的安装与环境搭建 jdk8下载网址:https://www.oracle.com/cn/java/technologies/javase/javase-jdk8-downloads.html ...

  5. vue 倒计时 iOS无效

    vue实现的倒计时在苹果手机上无效,原因是因为后台返回的时间格式是'2019-1-29 17:13:04',而苹果手机只能解析这种时间格式'YYYY/MM/DD HH:mm:ss',修改后测试成功的代 ...

  6. 如何使用jQuery $.post() 方法实现前后台数据传递

    基础方法为 $.post(URL,data,callback); 参数介绍: 1.URL 参数规定您希望请求的 URL. 2.data 参数规定连同请求发送的数据. 3.callback 参数是请求成 ...

  7. 使用jhipster 加速java web开发

    jhipster,中文释义: Java 热爱者! JHipster is a development platform to quickly generate, develop, & depl ...

  8. java实现一个点餐系统

    转载于blog.csdn.net/weixin_44219955 项目大体框架 菜品类(菜品id,菜品名,菜品类型,上架时间,单价,月销售,总数量) 管理员类(管理员id,账号,密码) 客户类(客户i ...

  9. 归并排序(JAVA语言)

    public class merge { public static void main(String[] args) { // TODO Auto-generated method stub int ...

  10. python2文件开头两行

    #!/usr/bin/python  或者  #!/usr/bin/env python 告诉操作系统python位置 # -*- coding:utf-8 -*- 设置文件编码为utf-8  (默认 ...