倭マン's BLOG

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

FactoryBuilderSupport よ、我に力を! (4) : AbstractFactory クラスの isXxxx() メソッド

今回は AbstractFactory クラス(Factory インターフェース)に定義されている isXxxx() メソッドを見ていきます。

AbstractFactory クラスに定義されている isXxxx() メソッドは次の2つ:

  • isLeaf() メソッド
  • isHandlesNodeChildren() メソッド

もちろん、どちらも返り値は boolean です。 AbstractFactory のデフォルト実装(と Bean ファクトリ*1)での各メソッドの返り値は下表のようになってます:

isXxxx() メソッド AbstractFactory クラス Bean ファクトリ
isLeaf() false false
isHandlesNodeChildren() false false

では、それぞれのメソッドをもう少し詳しく見ていきましょう。

isLeaf() メソッド


isLeaf() メソッドは構築しようとしているノードが末端要素、つまり子ノードを持たないかどうかを返します。 持たない場合は true、持つ場合は false が返されます。

もし isLeaf() メソッドが true を返す場合、子ノードを構築しようとすると RuntimeException が投げられます。 また、このとき子ノードが構築されないので、同ファクトリ・オブジェクトの

  • isHandleNodesChildren() メソッド
  • onNodeChildren() メソッド
  • setChild() メソッド

は呼ばれません。

では、isLeaf() が true を返すようにしたサンプルコードを見てみましょう:

/* Bean クラス */
class Leaf{}

/* Leaf クラスのファクトリ */
class LeafFactory extends AbstractFactory{

    @Override Object newInstance(FactoryBuilderSupport builder, name, value, Map map) {
        return new Leaf()
    }

    // isLeaf() が true を返すように設定
    @Override boolean isLeaf() {
        return true
    }
}

/* ビルダー */
class TreeBuilder extends FactoryBuilderSupport{

    TreeBuilder(){
        registerFactory('leaf', new LeafFactory())
    }
}

// スクリプト
def builder = new TreeBuilder()
try{
    builder.leaf{    // RuntimeException が投げられる
        leaf()
    }
    assert false

}catch(RuntimeException e){
    assert true
}

leaf ノードが子要素を持っているので、ビルダーによる構築時に RuntimeException が投げられます。

isHandlesNodeChildren() メソッド


isHandlesNodeChildren() メソッドは構築しようとしているノードの「子ノードを操作する」かどうかを返します。 ここで「子ノードを操作する」とは、同ファクトリ・オブジェクトの onNodeChildren() メソッドを呼び出すかどうかということです。 注意が必要なのは、isHandlesNodeChildren() メソッドの返り値に関係なく、子ノードの(対応するファクトリによる)構築は行われます。

isHandlesNodeChildren() メソッドが false を返す場合のサンプルを見てみましょう:

/* Bean クラスその1 */
class Leaf{}

/* Leaf のファクトリ */
class LeafFactory extends AbstractFactory{

    // Leaf オブジェクトが生成されたら "Create Leaf" と表示
    @Override Object newInstance(FactoryBuilderSupport builder, name, value, Map map) {
        println 'Create Leaf'
        return new Leaf()
    }
}

/* Bean クラスその2 */
class Branch{}

/* Branch のファクトリ */
class BranchFactory extends AbstractFactory{

    @Override Object newInstance(FactoryBuilderSupport builder, name, value, Map map) {
        return new Branch()
    }

    // isHandesNodeChildren() が false を返すように設定
    @Override boolean isHandlesNodeChildren() {
        return false
    }

    // 呼ばれるとアサーションが失敗
    @Override boolean onNodeChildren(FactoryBuilderSupport builder, node, Closure content) {
        assert false
    }
}

/* ビルダー */
class TreeBuilder extends FactoryBuilderSupport{

    TreeBuilder(){
        registerFactory('leaf', new LeafFactory())
        registerFactory('branch', new BranchFactory())
    }
}

// スクリプト
def builder = new TreeBuilder()
def tree = builder.branch{
    leaf()    // "Create Leaf" と表示される
}

このスクリプトは例外が投げられずに終了し、標準出力に "Create Leaf" と表示されます。 BranchFactory の onNodeChildren() メソッドは呼ばれず、一方、LeafFactory の newInstance() メソッドは呼ばれています。

Groovy for Domain-specific Languages

Groovy for Domain-specific Languages


数学ガール 乱択アルゴリズム (数学ガールシリーズ 4)

数学ガール 乱択アルゴリズム (数学ガールシリーズ 4)

*1:FactoryBuilderSupport クラスに registerBeanFactory() メソッドで登録される Factory オブジェクト