悠然乱弹:从几个方法的重构讲开去--注解相关的处理-阿里云开发者社区

开发者社区> 开发与运维> 正文

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

简介:

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

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

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

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

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

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

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

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

版权声明:本文首发在云栖社区,遵循云栖社区版权声明:本文内容由互联网用户自发贡献,版权归用户作者所有,云栖社区不为本文内容承担相关法律责任。云栖社区已升级为阿里云开发者社区。如果您发现本文中有涉嫌抄袭的内容,欢迎发送邮件至:developer2020@service.aliyun.com 进行举报,并提供相关证据,一经查实,阿里云开发者社区将协助删除涉嫌侵权内容。

分享:
开发与运维
使用钉钉扫一扫加入圈子
+ 订阅

集结各类场景实战经验,助你开发运维畅行无忧

其他文章