SeamFramework.orgCommunity Documentation

Capítulo 8. Decoradores

8.1. Atributos delegados
8.2. Habilitando decoradores

Interceptadores são um meio poderoso para capturar e separar preocupações ortogonais para o tipo de sistema. Qualquer interceptador é capaz de interceptar invocações de qualquer tipo Java. Isso os torna ideais para resolver questões técnicas, tais como gerenciamento de transação e segurança. No entanto, por natureza, interceptadores desconhecem a real semântica dos eventos que interceptam. Assim, interceptadores não são um instrumento adequado para a separação de questões relacionadas a negócios.

O contrário é verdadeiro decoradores. O decorador intercepta invocações apenas para uma determinada interface Java e, portanto, é ciente de toda a semântica que acompanha a interface. Isso torna os decoradores uma ferramenta perfeita para modelar alguns tipos de questões de negócios. Significa também que um decorador não tem a generalidade de um interceptador. Decoradores não são capazes de resolver questões técnicas que atravessam muitos tipos diferentes.

Suponha que temos uma interface que represente contas:

public interface Account {

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

Vários Web Beans em nosso sistema implementam a interface Account. No entanto, temos uma obrigação legal que, para qualquer tipo de conta, as grandes transações devem ser registadas pelo sistema, em um registro especial (log). Esse é um trabalho perfeito para um decorador.

Um decorador é um Web Bean simples que implementa o tipo que decora e é anotado com @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) );
        }
    }
    
}

Ao contrário de outros Web Beans simples, um decorador pode ser uma classe abstrata. Se não há nada de especial que o decorador precisa fazer para um determinado método da interface decorada, você não precisa implementar esse método.

Todos os decoradores têm um atributo delegado. O tipo e os tipos de binding do atributo delegado determinam a qual Web Beans o decorador está vinculado. O tipo do atributo delegado deve implementar ou estender todas as interfaces implementadas pelo decorador.

Este atributo delegado especifica que o decorador está vinculado a todos os Web Beans que implementam Account:

@Decorates Account account;

Um atributo delegado pode especificar uma anotação de binding. Então, o decorador só será vinculado ao Web Beans com o mesmo vínculo.

@Decorates @Foreign Account account;

Um decorador é vinculado a qualquer Web Bean que:

O decorador pode invocar o atributo delegado,o que praticamente equivale a chamar InvocationContext.proceed() a partir de um interceptador

Nós precisamos habilitar nosso decorador no web-beans.xml.


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

Essa declaração tem o mesmo propósito para decoradores que a <Interceptors> tem para os interceptadores:

Interceptadores para o método são chamados antes dos decoradores que se aplicam a esse método.