原创作者: 江南白衣   阅读:4659次   评论:0条   更新时间:2011-05-26    
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对象定义为不能删除,Dao基类的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(Book.class)){
    ...
}
//根据Bean实体判断
if(bookinstanceof 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;
    }
} 


在框架中的判断:

if (entityClass.isAnnotationPresent(Undeletable.class)) {
    Undeletable anno = (Undeletable) entityClass.getAnnotation(Undeletable.class);
    statusProperty = anno.status();
}

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

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

   BTW.标题太长了,其实也属于幼学琼林系列,show一下用interface 和 annotation 定义元数据,交给框架去反射的基本写法。

评论 共 0 条 请登录后发表评论

发表评论

您还没有登录,请您登录后再发表评论

文章信息

Global site tag (gtag.js) - Google Analytics