服务热线:13616026886

技术文档 欢迎使用技术文档,我们为你提供从新手到专业开发者的所有资源,你也可以通过它日益精进

位置:首页 > 技术文档 > JAVA > 新手入门 > 基础入门 > 查看文档

侵入,无侵入? annotation vs interface

   1. interface

   使用interface 定义对象的类型,框架根据对象的接口来提供服务,这种模式是古而有之的java框架设计者必习之法,从最重量的ejb到最轻量的spring,都离不开这种方式,也的确解决了很多问题。比如在大家熟悉的spring里:

  • beanfactoryaware接口,框架看到它就会调用bean的setbeanfactory(beanfactory beanfactory) 函数,将beanfactory传给它,让它自行用beanfactory获得更多bean,而不仅限于依赖注入的bean。
  • factorybean接口,框架看到它就不会把这个bean放入自己的context,而是调用它的getobject()函数,将返回的结果作为bean放入。spring里很多功能依赖于这个扩展机制,因为它可以用factory模式返回任意类型对象,而不是<bean class="foo">中class指定类型。
  • initializingbean接口,因为很多bean在各setter注入后,还需要一个总的init函数进行初始化,比如需要同时根据注入的属性a和 b,来初始化属性c的值。这时候框架就会调用afterpropertiesset() 初始化。

        等等,最后一个initializingbean接口很邪恶阿!!硬要pojo实现一个名字怪怪的afterpropertiesset()函数,侵入得不能再侵入阿。

   2. 无侵入

        所以,spring提供了另一种方式,在配置文件里定义初始方法的名字: <bean class="foo" init-method="init"/>

        其实spring提倡的无侵入有两种层次:

        一种是像quartz,jmx,webservice这些模块,pojo啥都不用做,spring使用aop,factorybean这样的机制使它们白日飞升具备了webservice,定时执行的能力。

        一种是像init-method的例子,pojo并不很明显的实现spring的接口,知觉spring的存在,自己实现自己的函数,然后由spring的配置文件去调用它们。

        前一种无侵入的作用非常明显,后一种的意义就看具体的场景了,有时候实现一下spring的接口也没什么所谓,但有时候各种原因会希望不显式的实现接口。

 3. annotation   

      在jdk5新增了annotation的模式。annotation 模式是xml模式的竞争者,但题目太大本篇就不讨论了,我的观点是主要看数据属于配置数据还是代码元数据。

      本文forcus interface vs annotation来定义对象类型和行为。

  最开始用annotation 使java代码不再那么受传统模式局限的是testng,然后junit 4紧跟其后,在默认机制之外,可以用annotation 来灵活定义setup函数和测试函数。

   4. 对比演示

  下面,我们以springside里的undeleteentity接口和@undelete 标识的实现,具体演示一下两者。

  需求是如果把entity对象定义为不能删除,则基类的remove函数就不会真正删除该对象,而是设置状态列为"无效"。

 

interface是这样实现的:

interface 定义:

public interface undeletableentity {
    void setstatus(string status);
}

interface 在entity使用:

public class book implements undeletableentity {
  private string status;  public void setstatus(string status) {
   this.status = status;
  }
 }

interface 在框架中使用:

//根据class 判断
if(undeletableentity.class.isassignablefrom(entityclass)){
    ...
}

//根据bean实体判断
if(bean instanceof undeletableentity{
   ((uldeletableentity)bean).setstatus("-1");
}

    大家都很熟悉的写法,就不解释了。

annotation是这样实现的:

   annotation 定义:

@target({elementtype.type})
@retention(retentionpolicy.runtime)
public @interface undeletable {
  string status() default "status";
}

   原本怪sun怎么这么抠门,用@interface 而不另外搞一个关键字,原来sun的意思就是把interface和annotation的定位一样呀。

   @target 定义annotation 可用于的地方,比如类型,函数,函数参数等。type代表class,interface...

   @retention(retentionpolicy.runtime)表明是个运行期的annotation,否则后面的代码都不会起作用。

   string status() 定义了annotation有个status的属性,而且可以不定义,默认为status。

   annotation在entity使用:

@undeletable
  public class book{
    private string status;
     public void setstatus(string status) {
        this.status = status;
     }
  }

@undeletable(status = "status2")
    public class bookwithnewstatus {
    private string status2;
    public void setstatus2(string status2) {
        this.status2 = status2;
    }
}

annotation在框架中的使用:

if (entityclass.isannotationpresent(undeletable.class)) {
    undeletable anno = (undeletable) entityclass.getannotation(undeletable.class);
    statusproperty = anno.status();
}

   可见,annotation的模式,比interface要少一点侵入性,不定死status列的名称,而且还可以灵活定义更多元属性,比如定义无效时的值为"-1","unvalid"。

   但是,这种模式也和所有动态的东西向一样,失去了编译期校验的优势,pojo如果没有setstatus() 这个函数在编译期也检查不出来。

扫描关注微信公众号