SeamFramework.orgCommunity Documentation
拦截器能够以一种强大的方式来捕获和分离关注点,拦截器和类型系统的关系是正交的。任何拦截器都能够拦截任何Java类型的调用。这种特性能够让拦截器很好的处理技术关注点,例如事务管理和安全。不过,拦截器无法领会其所拦截时间的真实语义。因此,拦截器并不是分离业务相关的关注点的好工具。
对装饰器来说,反之亦然。一个装饰器只拦截特定Java接口的调用,因此它能够领会这个接口关联的语义。装饰器的特性使其成为某些业务关注点的理想的建模工具。这也意味着装饰器并不拥有一个拦截器的普遍性。装饰器无法解决跨越多个不同类型的技术关注点。
假定我们有一个表现帐户的接口:
public interface Account {
public BigDecimal getBalance();
public User getOwner();
public void withdraw(BigDecimal amount);
public void deposit(BigDecimal amount);
}
我们系统实现中可以有多个不同的Web Beans实现 Account
接口。然而我们有一个通用的法律要求对于任何帐户,大的交易必须由系统在一个特定的日志中记录。装饰器非常适合处理这种工作。
装饰器是一个简单的Web Bean,能够实现其装饰的类型。装饰器使用 @Decorator
注释。
@Decorator
public abstract class LargeTransactionDecorator
implements Account {
@Decorates Account account;
@PersistenceContext EntityManager em;
public void withdraw(BigDecimal amount) {
account.withdraw(amount);
if ( amount.compareTo(LARGE_AMOUNT)
>0 ) {
em.persist( new LoggedWithdrawl(amount) );
}
}
public void deposit(BigDecimal amount);
account.deposit(amount);
if ( amount.compareTo(LARGE_AMOUNT)
>0 ) {
em.persist( new LoggedDeposit(amount) );
}
}
}
和其他简单的Web Beans不同,一个装饰器可以是一个抽象类。如果被装饰的接口中一个特殊方法对装饰器没有用处,那么装饰器可以不实现这个方法。
所有装饰器都有一个 委托属性 。委托属性的类型和绑定类型决定了装饰器绑定到哪个Web Bean上。委托属性类型必须实现或者继承装饰器实现的所有接口。
下面的委托属性指定了装饰器绑定到所有实现 Account
接口的Web Beans:
@Decorates Account account;
一个委托属性能够指定一个绑定注释。装饰器只能绑定具有相同绑定的Web Beans。
@Decorates @Foreign Account account;
一个装饰器可以绑定到任何符合下面条件的Web Bean上:
有一个作为API类型的委托属性类型,以及
具备委托属性声明的说有绑定类型。
装饰器可以调用委托属性,这和从一个拦截器中调用 InvocationContext.proceed()
具有相同效果。