首页 > 其他分享 >通过自定义注解和反射实现策略模式

通过自定义注解和反射实现策略模式

时间:2023-01-31 18:22:33浏览次数:45  
标签:反射 自定义 class value TypeEnum HandleType 注解 public

通过自定义注解和反射实现策略模式

​ 今天在写一个工单系统时,工单审批通过后,需要根据不同的工单类型选择不同的处理方式

非常适合用自定义注解+反射来实现,研究了一番,记录一下成果.

类型枚举类

先定义一个类型的枚举类

@AllArgsConstructor
@Getter
public enum TypeEnum {

    TYPE1(1,"类型一"),
    TYPE2(2,"类型二");

    private Integer value;

    private String desc;

    //定义这个静态变量,时为了方便通过类型编码获取到描述信息
    private final static Map<Integer, TypeEnum> ENUM_MAP =
            Maps.uniqueIndex(EnumSet.allOf(TypeEnum.class), TypeEnum::getValue);
    public static String getDesc(Integer value) {
        TypeEnum oneEnum = ENUM_MAP.get(value);
        if (oneEnum!=null){
            return oneEnum.getDesc();
        }
        return null;
    }
}

自定义注解类

@Documented
//ElementType.TYPE表示允许被修饰的注解作用在类、接口和枚举上,其他还有,FIELD(允许作用在属性字段上),METHOD(允许作用在方法上),PARAMETER(允许作用在方法参数上),CONSTRUCTOR(允许作用在构造器上),LOCAL_VARIABLE(允许作用在本地局部变量)上,ANNOTATION_TYPE(允许作用在注解上),PACKAGE(允许作用在包上)
//{}里面可以有多种类型,这里指用到了TYPE类型
@Target({ElementType.TYPE})
//表示自定义注解将存在到哪个生命周期,RetentionPolicy.SOURCE(注解只保留在源文件),RetentionPolicy.CLASS(注解被保留到class文件),RetentionPolicy.RUNTIME(jvm加载class文件之后,仍然存在)
@Retention(RetentionPolicy.RUNTIME)
//@Interited 用来声明一个注解
public @interface HandleType {
    //TypeEnum就是上面定义的枚举类型
    TypeEnum[] value();
}

定义公共接口和实现类

定义需要实现的功能

public interface HandleService {

    void handleMethed();

}

两个处理实现类

@Slf4j
@Service
//处理方式一
@HandleType(value = TypeEnum.TYPE1)
public class HandleOne implements HandleService {
    
    @Override
    public void handleMethed() {
        log.info("处理方式一执行!");
    }
    
}


@Slf4j
@Service
//处理方式二
@HandleType(value = TypeEnum.TYPE2)
public class HandleTwo implements HandleService {
    
    @Override
    public void handleMethed() {
        log.info("处理方式二执行!");
    }
    
}

启动时加载所有加了@HandleType注解的类的对象

@Slf4j
@Configuration
public class SpringBeanConfig {

    @Resource
    private ApplicationContext applicationContext;
    /**
     * 处理方式对象集合
     */
    private Map<Integer, HandleService> handleServiceMap = new HashMap<>();


    //@PostConstruct是Java自带的注解,在方法上加该注解会在项目启动的时候执行该方法,也可以理解为在spring容器初始化的时候执行该方法。@PostConstruct注解的方法将会在依赖注入完成后被自动调用
    @PostConstruct
    public void init() {
        //ApplicationContext 应用上下文 getBeansWithAnnotation()  根据注解类型获取的对应的 bean名称 和 bean对象
        //遍历bean对象
        applicationContext.getBeansWithAnnotation(HandleType.class).forEach((k, v) -> {
            //AnnotationUtils.findAnnotation(A.Class,B.Class)查找第A类中,是否涵盖B注解。如果有,就返回此注解,没有就返回空
            //@HandleType注解的value值可以有多个
            TypeEnum[] typeEnums = AnnotationUtils.findAnnotation(v.getClass(),HandleType.class).value();
            //遍历value值放到map中
            for (int i = 0; i < typeEnums.length; i++) {
                Integer type = typeEnums[i].getValue();
                handleServiceMap.put(type, (HandleService) v);
            }
        });
        log.info("Succeed to load service: {}", handleServiceMap);
    }

    public HandleService getHandleService(Integer type) {
        return handleServiceMap.get(type);
    }

}

根据不同处理类型,动态选择不同处理方式

@Service
@Slf4j
public class OrderService {
    
    @Resource
    private SpringBeanConfig springBeanConfig;

    //获取处理方式对象
    private HandleService getService(Integer handleType) {
        HandleService handleService = springBeanConfig.getHandleService(handleType);
        if (handleService == null) {
            log.info("handleType:{} baseService is null",handleType);
            return null;
        }
        return handleService;
    }
    
    //根据处理类型选择不同处理方式
    private void deal(String handleType) {
        HandleService handleService = getService(handleType);
        //处理业务数据
        handleService.handleMethed();
        log.info("业务数据处理完成");
    }
}

总结

HandleOne和HandleTwo是两种处理策略

TypeEnum定义了有哪几种策略

HandleType是自定义注解本体

SpringBeanConfig把所有的策略汇总到一个map中

OrderService具体的业务实现

标签:反射,自定义,class,value,TypeEnum,HandleType,注解,public
From: https://www.cnblogs.com/joule/p/17080149.html

相关文章

  • Taro 自定义地图并接入高德sdk
    小程序项目有用到需要自定义地图的需求,于是记录下操作流程1、引入高德地图sdk包下载地址:https://lbs.amap.com/api/wx/download2、项目中导入并初始化//导入impor......
  • mavon-editor自定义添加颜色选择器
    mavon-editor原本是没有带颜色选择器的,产品提出的需求,只好自定义一个了这里是看了源码再加上看别人的博客,然后加了个插槽,我使用的是elementui的颜色选择器el-color-picke......
  • 【转载】 spring 利用注解类添加日志到mysql
    一、前言我们写完一个项目,运维时,如果出现了bug,我们需要查看控制台的日志,但是那个日志无关方法太多,查找不是很方便,还有就是一个项目上线之后,我们需要记录谁操作了那些功能,......
  • grafana 自定义dashboard Variables
    Variables 示例VariablesDependenciesdashboard显示  ......
  • 微信小程序自定义导航栏机型适配
    自定义微信小程序头部导航栏,有几种方式方式一{"navigationStyle":"custom"//将navigationStyle从默认default改为custom}定义此方法后,头部的导航栏会去掉,导航......
  • vue3实现禁用物理按键返回,但是可以通过自定义app-bar的返回按钮返回
    1.注意app-bar是一个所有页面都会用到的顶部title栏,里面左侧有返回按钮;2.基于1,在app-bar组件的setup里添加这个代码:onMounted(()=>{//不能少history.pu......
  • django 自定义模版过滤器
    虽然DTL给我们内置了许多好用的过滤器。但是有些时候还是不能满足我们的需求。因此Django给我们提供了一个接口,可以让我们自定义过滤器,实现自己的需求。模版过滤器必须要......
  • CAD怎么自定义线型?CAD线型自定义步骤
    有些设计师小伙伴绘制CAD图纸的过程中,在调用CAD线型时,觉得软件中自带的线型不适用,想要自定义CAD线型,那么,CAD怎么自定义线型呢?本节教程小编就来给大家分享一下浩辰CAD软件中......
  • 直播电商平台开发,vue 自定义指令过滤特殊字符
    直播电商平台开发,vue自定义指令过滤特殊字符 /** *@tagsinput只可以輸入数字、字母、汉字 *@examplev-emoji */exportdefault(app)=>{ app.directive('e......
  • SAP UI5 应用如何加载自定义 Theme
    要加载外部自定义主题,开发人员可以通过在页面中静态声明或使用Core.setThemeRoot()方法来设置此主题。这非常类似于对位于不同位置的SAPUI5库使用registerModulePat......