悠然乱弹:从几个方法的重构讲开去--注解相关的处理

简介:

有时候它们的处理没有关联性,有些时候,它们的处理又是有关联性的。

我们用伪代码来示意一下。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
if (includeAnnotation(testClass,Abc. class )){
   doSomething...
}
 
if (includeAnnotation(testClass,Abc. class )){
   for (Field field:testClass.getFields){
     if (includeAnnotation(testField,AbcField. class )){
      dosomething...
    }
   }
   for (Method method:testClass.getMethods){
     if (includeAnnotation(testMethod,AbcMethod. class )){
      dosomething...
    }
   }
}
你会发现所有的注解过程处理都是上面几种情况。

有的时候,我们可能在类名的处理上还有一些规则,比如:....Service,.....Action,.....View等等,我们的某些注解只可以加在某种类名规则之下,这个时候,判定就又会增加。我们的程序员就不停的在写这些重复,但是却不可缺少的内容。有没有办法让开发人员只写doSomething的内容就好呢??

只要问题可以提得出来,办法总是有的:

可以定义下面的三个类,开发人员只要编写process函数体中的内容就好了。

?
1
2
3
4
5
6
7
8
9
public interface AnnotationClassAction {
     <T> void process(Class<T> clazz, Annotation annotation);
}
public interface AnnotationMethodAction {
     <T> void process(Class<T> clazz, Method method, Annotation annotation);
}
public interface AnnotationPropertyAction{
     <T> void process(Class<T> clazz, Field field, Annotation annotation);
}

这对于开发人员来说当然是再熟悉不过的了。

但是总要让上面的逻辑有所体现才是,否则不是就执行错位置了??

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
< annotation-class-matchers >
     < annotation-class-matcher class-name = ".*\.annotation\.Annotation.*"
         annotation-type = ".*Test" >
         < processor-beans >
             < processor-bean enable = "true" name = "classAction" >
             </ processor-bean >
         </ processor-beans >
         < annotation-method-matchers >
             < annotation-method-matcher method-name = "method.*"
                 annotation-type = ".*Test" >
                 < processor-beans >
                     < processor-bean enable = "true" name = "methodAction" >
                     </ processor-bean >
                 </ processor-beans >
             </ annotation-method-matcher >
         </ annotation-method-matchers >
         < annotation-property-matchers >
             < annotation-property-matcher
                 property-name = "field.*" annotation-type = ".*Test" >
                 < processor-beans >
                     < processor-bean enable = "true" name = "propertyAction" >
                     </ processor-bean >
                 </ processor-beans >
             </ annotation-property-matcher >
         </ annotation-property-matchers >
     </ annotation-class-matcher >
</ annotation-class-matchers >

上面的演示了一个 示例,看起来比较复杂,其实是因为配置的内容为了充分说明,所以看起来有点复杂,实际应用情况不一定要全配的。我给翻译一下:

?
1
2
3
4
5
首先进行注解类的匹配,匹配的类名是*.annotation.Annotation.*,上面加的注解名是*Test,如果匹配呢,就执行classAction处理器。
 
如果类名匹配,则再进行方法匹配,方法名必须是method*格式的,上面加的注解是*Test类型的注解,匹配成功呢就执行methodAction处理器。
 
如果类名匹配,再进行属性匹配,属性名必须为field*格式,上面的注解格式是*Test类型,如果匹配呢就执行propertyAction处理器。

这样是不是简单了,把所有的匹配工作都通过配置的方式进行实现,开发人员只需要做逻辑处理的部分。

比如下面这样子:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class AnnotationClassActionDemo implements AnnotationClassAction {
     public <T> void process(Class<T> clazz, Annotation annotation) {
         System.out.println( "className:" + clazz.getName() + " annotation类型:"
                 + annotation.annotationType().getName());
     }
}
 
public class AnnotationMethodActionDemo implements AnnotationMethodAction {
     public <T> void process(Class<T> clazz, Method method,
             Annotation annotation) {
         System.out.println( "className:" +clazz.getName()+ " annotation类型:" +annotation.annotationType().getName()+ " method名称:" +method.getName());     
     }
}
 
public class AnnotationPropertyActionDemo implements
         AnnotationPropertyAction {
 
     public <T> void process(Class<T> clazz, Field field, Annotation annotation) {
         System.out.println( "className:" + clazz.getName() + " annotation类型:"
                 + annotation.annotationType().getName() + " field名称:"
                 + field.getName());
     }
}
针对下面的类:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@Test (id= 0 ,description= "class" )
@XStreamAlias ( "sd" )
public class AnnotationDemo1 {
     @Test (id= 1 ,description= "field1" )
     private String field1;
     @Test (id= 2 ,description= "field2" )
     private String field2;
     @Test (id= 3 ,description= "method1" )
     public void method1(){
         System.out.println( "method1" );
     }
     @Test (id= 4 ,description= "method2" )
     public void method2(){
         System.out.println( "method2" );
     }
     public String getField1() {
         return field1;
     }
     public void setField1(String field1) {
         this .field1 = field1;
     }
     public String getField2() {
         return field2;
     }
     public void setField2(String field2) {
         this .field2 = field2;
     }
}

进行处理,可以看到正确的处理结果。

?
1
2
3
4
5
className:org.tinygroup.annotation.AnnotationDemo1 annotation类型:org.tinygroup.annotation.Test
className:org.tinygroup.annotation.AnnotationDemo1 annotation类型:org.tinygroup.annotation.Test field名称:field1
className:org.tinygroup.annotation.AnnotationDemo1 annotation类型:org.tinygroup.annotation.Test field名称:field2
className:org.tinygroup.annotation.AnnotationDemo1 annotation类型:org.tinygroup.annotation.Test method名称:method1
className:org.tinygroup.annotation.AnnotationDemo1 annotation类型:org.tinygroup.annotation.Test method名称:method2

通过上面的的重构,我们可以看到,把开发人员从重复的劳动中解脱出来,而且由于其只处理逻辑部分的内容即可,也避免了一些不必要的逻辑错误引入。

当然,采用配置还是编码的方式配置匹配规则,这个是公说公有理,婆说婆有理,其实两者都支持不就可以了??

总之,通过上面的重构,对编程人员开发注解方面有更大的便捷。

通过文件处理及注解处理的重构,我们看到代码编写及实现确实是优雅了,

解决了代码重复、圈复杂度大、扩展方面的问题,但是性能方面的问题其实是还没有解决的。

相关文章
|
5月前
|
存储 消息中间件 前端开发
PHP后端与uni-app前端协同的校园圈子系统:校园社交场景的跨端开发实践
校园圈子系统校园论坛小程序采用uni-app前端框架,支持多端运行,结合PHP后端(如ThinkPHP/Laravel),实现用户认证、社交关系管理、动态发布与实时聊天功能。前端通过组件化开发和uni.request与后端交互,后端提供RESTful API处理业务逻辑并存储数据于MySQL。同时引入Redis缓存热点数据,RabbitMQ处理异步任务,优化系统性能。核心功能包括JWT身份验证、好友系统、WebSocket实时聊天及活动管理,确保高效稳定的用户体验。
329 5
PHP后端与uni-app前端协同的校园圈子系统:校园社交场景的跨端开发实践
|
5月前
|
Java Linux
自定义linux脚本用于快速jar包启动、停止、重启
自定义linux脚本用于快速jar包启动、停止、重启
284 29
|
数据采集 运维 前端开发
我用三个月时间仿造了一个稿定设计 | 2022年中总结
回想当时我还在做着一些零散的项目需求,这时候领导给了我一个任务,说让我重构一个“在线PS”,我就在这样一个没有产品、没有UI、研发只有1人、开发工时约等于没有的情况下,在追逐竞品的无限挫败感中,勉强完成了第一版的开发。
|
监控 物联网 流计算
IOT/智能设备日志解决方案(3):上下游对接
当数据从遍布全球的设备端以及服务端采集上来后,最先会到达数据队列。队列承载所有数据的入口和出口,必须具备的两大能力是: * 丰富的上下游对接能力:数据要能从各种方式接入上来,也能够非常容易的对接各个系统。
3443 0
IOT/智能设备日志解决方案(3):上下游对接
DB9_公头_母头_串口引脚定义及RS-232串口线制作方法
RS-232连接线制作方法 材料及工具 一根双绞线(8芯)、一个标准RJ45头、一个DB9孔型插头、一把RJ45专用工具、一个电烙铁及若干焊锡。 引脚定义 按以下管脚定义制作RJ45端头;I表示网络视频服务器输入,O表示网络视频服务器输出。
4678 0
|
Kubernetes 网络协议 应用服务中间件
Kubernetes(k8s)如何使用kube-dns实现服务发现
大纲: Kubernetes中如何发现服务 如何发现Pod提供的服务 如何使用Service发现服务 如何使用kube-dns发现服务 kube-dns原理 组成 域名格式 配置 注:本次分享内容基于Kubernetes 1.2版本! 下面从一个简单的例子开始讲解。
3791 0
|
机器学习/深度学习 缓存 网络协议
阿里DNS:一种不断变化前缀域名攻击检测方法
不断变化前缀域名攻击是DNS系统经常会遭受的一种典型攻击类型。那么有没有一种自动化的域名攻击检测方法,可以快速地判断是否是一种不断变化前缀域名攻击类型,并且自动提取攻击特征呢? 今天【阿里DNS】为您介绍一种不断变化前缀域名攻击检测方法,自动化地完成攻击特征的识别和提取。
华为手机怎么设置APP开机启动管理将自动管理修改成手动管理?
华为手机APP启动管理为分自动管理和手动管理,开启自动管理后将采用智能方式开启或关闭手机APP应用是否随手机启动自启或后台自启,采用手动管理模式可以最大可能的保证指定的手机APP应用开机或后台中自启动、允许关联启动、允许后台活动等。
5935 0