倭マン's BLOG

くだらない日々の日記書いてます。 たまにプログラミング関連の記事書いてます。 書いてます。

FactoryBuilderSupport よ、我に力を! (3) : ネスト構造のビルド

今回はやっとネスト構造を構築するビルダー。 なるべく簡単なサンプルを見ていきます。

ノードを構築するスクリプト


今回は、まずビルダーでオブジェクトを構築するスクリプトから見ていきましょう。 前回までに作った MathGirl オブジェクトを構築する mathGirl ノードが使えるとして、それらを子ノードとする girls ノードから、MathGirl オブジェクトの List を構築できるようにします。 スクリプトはこんなの:

def builder = new MathGirlBuilder()

// ビルダーによる構築
def girls= builder.girls{
    mathGirl(name:'Milka', age:17, ability:'Mathematics')
    mathGirl(name:'Tetora', age:16, ability:'English')
    mathGirl(name:'Yuri', age:14, ability:'Logic')
}

assert girls.collect{ it.name }.join(', ') == 'Milka, Tetora, Yuri'

ちょっとはビルダーらしくなってきたかな。

ファクトリ・クラス


では、実際に実装していきましょう。 今回は構築するオブジェクトを List オブジェクトにするので、構築対象のクラス(前回までの Bean クラス)を新たに作る必要はなし。 なのでファクトリ・クラスを作っていきます。

ネストノードを許すファクトリ・クラスを作るにもやはり AbstractFactory クラスを継承して Factory インターフェースのサブクラスを作成します。 AbstractFactory クラスのサブクラスを作るには newInstance() メソッドを実装する必要がありましたが、ネストされたノードからオブジェクトを構築する場合には構築されたオブジェクトにも対応するネスト構造を入れる必要があるために、大抵、これに加えて

  • setChild()
  • setParent()

のいずれかもしくは両方を実装します。 これらのメソッドの違いは、あるノードの親子関係を考えたときに

  • setChild() ・・・ 親ノードを構築するファクトリに対して呼ばれる
  • setParent() ・・・ 子ノードを構築するファクトリに対して呼ばれる

となっています。 今回のサンプルでは mathGirl ノードと girls ノードに親子関係がありますが

  • MathGirlFactory に対しては setParent() が呼ばれる
  • GirlsFactory に対しては setChild() が呼ばれる

となります*1。 今回はGirlsFactory クラスに setChild() メソッドを実装します:

class GirlsFactory extends AbstractFactory{

    @Override
    Object newInstance(FactoryBuilderSupport builder, name, value, Map atts) {
        return []
    }

    @Override
    void setChild(FactoryBuilderSupport builder, node, child) {
        assert child instanceof MathGirl    // 念のため子ノードから構築されるオブジェクトの型を確認
        node << child
    }
}

newInstance() メソッドでは単純に List オブジェクトを作成し、setChild() メソッドでは子ノードから構築された MathGirl オブジェクトをその List オブジェクトに追加しています。

ビルダーへの登録


ビルダーへの登録方法は、前回と同じく FactoryBuilderSupport#registerFactory() メソッドによって行います:

class MathGirlBuilder extends FactoryBuilderSupport{

    MathGirlBuilder(){
        registerBeanFactory('mathGirl', MathGirl)
        registerFactory('problem', new MathProblemFactory())

        // GirlsFactory の登録
        registerFactory('girls', new GirlsFactory())
    }
}

これで最初に載せたサンプルが動きます。 ネスト構造、恐るるに足らず。

Groovy for Domain-specific Languages

Groovy for Domain-specific Languages


数学ガール (数学ガールシリーズ 1)

数学ガール (数学ガールシリーズ 1)

*1:構築時には MathGirlFactory#setParent() → GirlsFactory#setChild() の順で呼ばれるようです。