SeamFramework.orgCommunity Documentation

章 8. 裝飾器(Decorators)

8.1. Delegate(類別;表示委派)屬性
8.2. 啟用裝飾器

呼叫攔截器(Interceptors)是個用來擷取和區分與型別系統垂直的相關問題的強大方式。任何攔截器皆可攔截任何 Java 類型的調用(invocation)。這使它們適用於解決涉及技術上的問題,例如交易管理和安全性。不過,就一般來講,攔截器並不會知道它們所攔截的事件之實際 語。因此,攔截器並不適合作為一個區分涉及商業問題的工具。意

裝飾器(decorators)則是相反的。裝飾器只會針對於特定 java 介面來攔截調用,因此它知道該介面的所有語意。這使得裝飾器適用於模擬涉及商業上的問題。同時這也代表裝飾器並沒有攔截器的普遍性。裝飾器無法解決涉及多種不同類型的技術問題。

假設我們有個顯示帳號的介面:

public interface Account {

    public BigDecimal getBalance();
    public User getOwner();
    public void withdraw(BigDecimal amount);
    public void deposit(BigDecimal amount);
}

我們的系統中會有幾個不同的 Web Bean 實做 Account 介面。不過,我們有個法律上的統一規定需求,那就是不管是任何哪種類型的帳號,大型的交易都必須被系統記錄於一個特殊的日誌中。這是一項適合裝飾器的工作。

裝飾器(decorator)是個單純的 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 Bean 不同的是,裝飾器可能會是個抽象類別(abstract class)。若裝飾器無須為被裝飾之介面的特定 method 進行任何特殊動作的話,您便無須實做該 method。

所有的裝飾器都有個 delegate 屬性。delegate 屬性的類型以及綁定類型可斷定裝飾器應綁定至哪些 Web Bean。delegate 屬性類型必須實做或是延伸裝飾器所實做的所有介面。

下列 delegate 屬性指出裝飾器已綁定至所有實做 Account 的 Web Bean:

@Decorates Account account;

Delegate 屬性可指定一個 binding annotation(綁定註解)。如此一來裝飾器便只會綁定至含有相同 binding 的 Web Bean。

@Decorates @Foreign Account account;

一個裝飾器會綁定至任何符合以下條件的 Web Bean:

裝飾器能夠引動 delegate 屬性,這和透過一個攔截器調用 InvocationContext.proceed() 的效果大致相同。

我們需要在 web-beans.xml啟用我們的裝飾器。


<Decorators>
    <myapp:LargeTransactionDecorator/>
</Decorators
>

此宣告(declaration)對於裝飾器的目的和 <Interceptors> 宣告對於攔截器的目的是相同的:

一個 method 的攔截器會於套用至該 method 的裝飾器之前先被調用。