デコレータ

今回はデコレータです。

【前提条件】

[環境]

【概要】

デコレータはGoFデザインパターンの一つです。
デコレータは既存のクラスに機能を追加するものです。

CDIによるデコレータは
インジェクション対象に機能を追加します。

【サンプルコード】

[インターフェイス]

デコレータのインターフェイスです。

package jp.glory.application;

public interface SampleDecoratorApplication {

    void execute();
}

普通のPOJOです。

[実行クラス]

インターフェイスを実装したクラスです。

package jp.glory.application.impl;

import jp.glory.application.SampleDecoratorApplication;

public class SampleDecoratorApplicationImpl implements SampleDecoratorApplication {

    @Override
    public void execute() {

        System.out.println("test");
    }

}

こちらもインターフェイスをimplementsしているだけの
普通のPOJOです。

[デコレータ]

機能を追加するクラスです。

package jp.glory.common.decorator;

import javax.decorator.Decorator;
import javax.decorator.Delegate;
import javax.inject.Inject;

import jp.glory.application.SampleDecoratorApplication;

@Decorator
public class SampleDecorator implements SampleDecoratorApplication {

    @Inject
    @Delegate
    private SampleDecoratorApplication applicaiton;

    @Override
    public void execute() {

        System.out.println(applicaiton.getClass().getSimpleName() + "#before");

        applicaiton.execute();

        System.out.println(applicaiton.getClass().getSimpleName() + "#after");
    }
}

デコレータのクラスには
javax.decorator.Decoratorアノテーションをつけます。

インターフェイスのimplementsとインジェクションをします。
インジェクションするオブジェクトには
javax.decorator.Delegateアノテーションをつけます。

オーバーライドしたメソッドの中で、
インジェクション↓オブジェクトのメソッドの実行と
前後の処理を追加します。

[beans.xml]

作成したデコレータを有効にするには
beans.xmlに設定を追加します。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://docs.jboss.org/cdi/beans_1_0.xsd">

    <decorators>
        <class>jp.glory.common.decorator.SampleDecorator</class>
    </decorators>
</beans>

decoratorsタグの下に作成したクラスの定義を追加します。

[その他のコード]

[ManagedBean]

package jp.glory.ui.impl;

import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;

import jp.glory.application.SampleDecoratorApplication;

@Named(value = "sampleDC")
@RequestScoped
public class SampleDecoratorPage {

    @Inject
    private SampleDecoratorApplication application = null;

    public void delegate() {

        application.execute();
    }
}

他のクラスからインジェクションするときは
デコレータを意識する必要はありません。

[ページ]

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:h="http://java.sun.com/jsf/html">
    <f:view>
        <h:form id="DecoratorForm">
            <h:commandButton action="#{sampleDC.delegate()}" value="テスト" />
        </h:form>
    </f:view>
</html>

[実行]

画面からボタンをクリックした時に
出力されたコンソールの結果です。

情報: SampleDecoratorApplicationImpl$Proxy$_$$_WeldSubclass#before
情報: test
情報: SampleDecoratorApplicationImpl$Proxy$_$$_WeldSubclass#after

デコレータとデコレートされたクラスが実行されているのがわかります。