Annotation VS. XML VS. interface

 Annotation

Annotation是jdk5的新玩意,作用是为代码中的元素(包,类,变量,方法等)添加信息(metadata)。
简单的例子:

@Retention(RetentionPolicy.RUNTIME)
@Target(
{ElementType.METHOD,ElementType.TYPE} )
public  @ interface  TestAnon  {
    String word()
default "hello world";
}

Annotation和类一样也是一个java文件。这就说明它和class interface一样,都是一种Type。定义Annotation的关键字 @interface

@Retention 指明了这个Annotation的作用范围,可选的枚举有SOURCE,CLASS,RUNTIME。
SOURCE就只在保留源代码里,CLASS指明编译成class文件中依然存在,RUNTIME指在运行中jvm能获取这个Annotation。

@Target表明这个Annotation用在什么地方,可以看到有方法,类,变量等选择

String word()定义了TestAnon 有个叫word的属性,默认值hello world。注意这里定义的属性只能是基本类型,String,Class,annotation或者这些类型数组

使用TestAnon

@TestAnon()
public   class  Test  {
    
public static void main(String[] a){
        Class
<Test> cl = Test.class;
        
if(cl.isAnnotationPresent(TestAnon.class)){
            TestAnon anno 
= cl.getAnnotation(TestAnon.class);
            System.out.println(anno.word());    
        }

    }

}

OK,运行后又看到了万恶的hello world。。。

Annotation有什么用?
除了打印这该死的hello world还有什么用?为什么需要Annotation?
首先看看Annotation到底是什么:从上面的例子可以看到,sun又添加了一种全新的代码元素,而这种元素专门用来解释其他的代码元素,并且提供了reflect的支持,换句话说,jdk5又提供了一种在代码中加入附加信息的手段。
再看看定义Annotation的关键字@interface。。这是否意味着他起到和interface类似的作用?
interface的功能无非就是告诉你,这个对象会有些什么样的方法。纯粹从功能上看,再次强调纯粹从功能上看:Annotation一样能做到,xml也能。。
看个实际例子:如果在某个方法内,我需要接收到一个对象,而先要对这个对象进行校验,才能继续下一步工作(如struts里面页面组装formbean)。
这是interface应用的典型场景,定义一个接口,由具体对象去具体实现:

public   interface  validateObj  {
        
boolean validate();
    }


    
public   class  TestObject  implements  validateObj  {

        
private int i;

        
private String str;

        
public boolean validate() {
            
if (i < 0 || i > 100)
                
return false;
            
if (str == null || str.length() > 20)
                
return false;
            
return true;
        }


    }

在接收到对象的地方:

validateObj obj  =  (validateObj)object;
            
if (obj.validate()) {
                
// do something here
            }

下面show下如何用Annotation做同样的事情:
首先定义一个Annotation用来标记可以校验的对象,注明是运行期,可作用于类型的Annotation。有2个属性分别是校验的方法名和参数(这里加参数只是为了说明普遍性)。

@Retention(RetentionPolicy.RUNTIME)
@Target(
{ElementType.TYPE} )
public  @ interface  ValidateObj  {
    String vaildateMethod() 
default "validate" ;
    Class
<?>[] parameter();
}

在具体对象中使用:

@ValidateObj(parameter = {String.class} )
    
public   class  TestObject   {

        
private int i;

        
private String str;

        
public boolean validate(String xx) {
            
if (i < 0 || i > 100)
                
return false;
            
if (str == null || str.length() > 20)
                
return false;
            
return true;
        }

    }

注意这里validate方法故意加了一个无意义的String参数,只是为了说明普遍性而已。
在接收到对象的地方:

boolean  reslut  =   false ;
        Class
<?>  clazz  =  obj.getClass();
        
if (clazz.isAnnotationPresent(ValidateObj. class )) {
            ValidateObj anno 
= clazz.getAnnotation(ValidateObj.class);
            
try {
                Method method 
= TestObject.class.getDeclaredMethod(anno.vaildateMethod(), anno.parameter());
                Object returnObj 
= method.invoke(obj,new Object[]{""});
                
if(returnObj instanceof Boolean){
                    reslut 
= (Boolean)returnObj;
                }

                
if(reslut){
                    
// do something
                }

            }
 catch (Exception e) {
                
// TODO Auto-generated catch block
                e.printStackTrace();
            }
 
        }

可以看到Annotation实现了上面接口完全一样的功能,甚至更为灵活,通过指定@ValidateObj不同的参数来使用不同的校验方法。
本质上接口也是一种配置信息,或者说配置信息同样是一种接口,那么显然用xml一样能实现同样的功能。

< Class  name ="com.abc.TestObj" >
    
< validateMehod > validate </ validateMehod >
    
< parameters >
        
< para > java.lang.String </ para >
    
</ parameters >
</ Class >

在校验的地方由对象的类名拿到校验方法名,找到后invoke即可。

why Annotation?

虽然功能上类似,但Annotation,interface,xml并不能互相取代,先谈谈interface和xml:
虽然你确实可以吧xml配置信息全部写在代码里来,用interface来做。但是这样往往需要设计复杂并且是项目独有的数据结构,想象下把struts-config写在代码里。而且改动配置信息后要重新编译。显然全局性质的配置信息,标准结构,工具齐全的xml是更好的选择。
具体举例:看hibernate的mapping文件。由pojo自己实现某个接口来得到OR mapping关系也是可行的,但是这个接口方法的返回值就必须是特殊结构复杂对象,并且为了使用框架就得每个pojo实现这个邪恶的接口,有一定的侵入性。而使用xml来使这些pojo白日飞升显然更方便。
另一方面,xml同样不可取代interface,使用xml来指定方法就失去了interface静态检查,结构清晰,代码可读性好的优点,增加了复杂性和出错可能性。不过同时也得到了一些无侵入的好处(spring就有这么做),所以在框架代码方面,有时候可能会用xml来取代interface,但在具体项目,具体业务中,不用interface去用xml就是丢西瓜建芝麻了。比如一个客户付账的业务方法,不同的客户类收费方式等具体业务不同,会有人用xml来做么?

Annotaion这种在代码中添加元数据的手段,更偏向于是xml的竞争者。不过序列化Serializable这样的接口用Annotation也无可厚非。
还是上文校验对象的例子,我们只是抽象出一个validate方法,但是假如现在对象的属性只有String,Integer2种类型,并且String只需要校验长度,匹配一个正则表达式,integer只有一个范围的校验。这样没有必要让业务对象去实现同样的逻辑。换句话说校验的抽象程度还不够。下面简单演示用Annotation来实现:

@Retention(RetentionPolicy.RUNTIME)
@Target(
{ElementType.FIELD} )
public  @ interface  StringValidate  {
    
int length();
    String pattern();
}

@Retention(RetentionPolicy.RUNTIME)
@Target(
{ElementType.FIELD} )
public  @ interface  IntValidate  {
    
int min();
    
int max();
}
public   class  TestObject {

        @IntValidate(min
=0,max=100)
        
private int i;

        @StringValidate(pattern
="^[A-Za-z]+$",length=20)
        
private String str;

    }

当然这个也能用xml来做,由类名,属性名取到具体的校验信息。不过使用Annotation最明显的好处就是不用配置文件代码来回切换,有编译器的编写帮助,出错可能性和直观性都强些。至于具体annotion or xml,那就是仁者见仁的问题了。

Annotation,interface,xml提供了3种添加信息的手段,这3个都不是银弹,各自有各自优缺点和适用的地方,技术发展的目的是为了更方便更简单,如果使用新东西让人觉得更复杂更麻烦,那这个新技术显然不适合这个项目。
so.. make it simple.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值