abhrshのSeasarにっき

2004-08-22

Strategyパターン

S2でStrategyパターンを使って動的にアルゴリズムを変更するサンプルを作ってみました。

方針はひがさんが言われている

Strategyが静的なものなら、普通にDIするだけです。 問題は、Strategyがデータに応じて動的に変わる場合です。 その場合は、StrategyのFactoryDIするようにします。 そして、必要なときに、データをStrategyのFactoryに 渡して、適切なStrategyを手に入れるのです。

はてなダイアリー - ひがやすをのここだけの話

に従っているつもりです。

お題は「一覧を取得するときにいくつかのソート順を切り替える」です。

まずはインターフェースの定義。

public interface GetSampleFactory {
    public static final String ORDER_ASC = "orderAsc";
    public static final String ORDER_DESC = "orderDesc";

    GetSampleLogic create(String key);
}

public interface GetSampleLogic {
    List getSample();
}

public interface SampleDao {
    List getSampleOrderAsc();
    List getSampleOrderDesc();
}

StrategyにあたるのはGetSampleLogicで、GetSampleFactoryが適切なGetSampleLogicの実装を提供します。

また、GetSampleFactory#create(String)の引数に渡すことができる値は"orderAsc"と"orderDesc"です。

SampleDaoには昇順と降順の2種類のListを取得できるメソッドがあります。

そして実装。

public class GetSampleFactoryImpl implements GetSampleFactory {
    private Map instanceMap = new HashMap();

    public void setOrderAsc(GetSampleLogic orderAsc) {
        instanceMap.put(ORDER_ASC, orderAsc);
    }

    public void setOrderDesc(GetSampleLogic orderDesc) {
        instanceMap.put(ORDER_DESC, orderDesc);
    }

    public GetSampleLogic create(String key) {
        return (GetSampleLogic) instanceMap.get(key);
    }
}

public class GetSampleOrderAsc implements GetSampleLogic {
    private SampleDao sampleDao;

    public void setSampleDao(SampleDao sampleDao) {
        this.sampleDao = sampleDao;
    }

    public List getSample() {
        return sampleDao.getSampleOrderAsc();
    }
}

public class GetSampleOrderDesc implements GetSampleLogic {
    private SampleDao sampleDao;

    public void setSampleDao(SampleDao sampleDao) {
        this.sampleDao = sampleDao;
    }

    public List getSample() {
        return sampleDao.getSampleOrderDesc();
    }
}

public class SampleDaoImpl implements SampleDao {
    public List getSampleOrderAsc() {
        return Arrays.asList(new String[] { "aa", "bb", "cc" });
    }

    public List getSampleOrderDesc() {
        return Arrays.asList(new String[] { "cc", "bb", "aa" });
    }
}

GetSampleFactoryImplが提供するGetSampleLogicの実装はsetterメソッドで渡すようにしました。これで実装クラスへの依存関係はdiconファイルで設定することができます。

GetSampleOrderAscとGetSampleOrderDescはGetSampleLogicの実装クラスです。SampleDaoのメソッド呼び出し以外は全く同じですね。(もう少しロジックがあるサンプルの方が良かったかも)

SampleDaoImplはSampleDaoの実装クラスです。

それでは、実行してちゃんと動くことを確かめたいと思います。

diconファイルとmain実行クラスです。



"http://www.seasar.org/dtd/components.dtd">
<components>
    <component name="sampleDao" class="strategy.SampleDaoImpl"/>

    <component name="getSampleOrderAsc" class="strategy.GetSampleOrderAsc"/>
    <component name="getSampleOrderDesc" class="strategy.GetSampleOrderDesc"/>

    <component name="getSampleFactory" class="strategy.GetSampleFactoryImpl">
        <property name="orderAsc">getSampleOrderAsc</property>
        <property name="orderDesc">getSampleOrderDesc</property>
    </component>
</components>

public class GetSampleFactoryClient {
    public static void main(String[] args) {
        S2Container container = S2ContainerFactory.create("strategy/strategy.dicon");
        GetSampleFactory factory = (GetSampleFactory) container.getComponent(GetSampleFactory.class);

        GetSampleLogic getSampleOrderAsc = factory.create(GetSampleFactory.ORDER_ASC);
        System.out.println(getSampleOrderAsc.getSample());

        GetSampleLogic getSampleOrderDesc = factory.create(GetSampleFactory.ORDER_DESC);
        System.out.println(getSampleOrderDesc.getSample());
    }
}

そして実行。

[aa, bb, cc]
[cc, bb, aa]

ちゃんと動きました~。これでStrategyもバッチリ

今回の場合は、Strategy部分の実装はDelegateInterceptorだけでもいけそうです。後でそっちでも動かしてみたいと思います。

Strategyパターン 捕捉

Strategyパターンとは本質的には関係ないですが、Strategy部分の実装をDelegateIntercepterに任せた場合も試しました。

diconファイルだけ差し替えます。(GetSampleOrderAscとGetSampleOrderDescは必要なくなります)



"http://www.seasar.org/dtd/components.dtd">
<components>
    <component name="sampleDao" class="strategy.SampleDaoImpl"/>

    <component name="getSampleOrderAsc" class="strategy.GetSampleLogic">
        <aspect>
            <component class="org.seasar.framework.aop.interceptors.DelegateInterceptor">
                <property name="target">sampleDao</property>
                <initMethod name="addMethodNameMap">
                    <arg>"getSample"</arg>
                    <arg>"getSampleOrderAsc"</arg>
                </initMethod>
            </component>
        </aspect>
    </component>

    <component name="getSampleOrderDesc" class="strategy.GetSampleLogic">
        <aspect>
            <component class="org.seasar.framework.aop.interceptors.DelegateInterceptor">
                <property name="target">sampleDao</property>
                <initMethod name="addMethodNameMap">
                    <arg>"getSample"</arg>
                    <arg>"getSampleOrderDesc"</arg>
                </initMethod>
            </component>
        </aspect>
    </component>

    <component name="getSampleFactory" class="strategy.GetSampleFactoryImpl">
        <property name="orderAsc">getSampleOrderAsc</property>
        <property name="orderDesc">getSampleOrderDesc</property>
    </component>
</components>

これで実行。

[aa, bb, cc]
[cc, bb, aa]

問題ないですね。

でもこれ使うとdiconファイルが読みづらくなってしまうなぁ。既にインターフェースが定義してあるから、こういう場合はDelegateInterceptorのメリットは少ないのかも。

zhsujdyjbrwzhsujdyjbrw 2012/02/17 18:05 pXRu4K , [url=http://gywanprthcww.com/]gywanprthcww[/url], [link=http://aizuwtjagvqm.com/]aizuwtjagvqm[/link], http://mibdprhmwfku.com/

ゲスト



トラックバック - http://seasarproject.g.hatena.ne.jp/abhrsh/20040822