例題で学ぶデザインパターン #6: Iterator の効能
例題で学ぶ Jython/Swing デザインパターン《Jython2.5》
Iterator の効能
■ 概要
例題により、アプリケーションを作成する過程を通して、Jython/Swing によるデザインパターンを習得します。
この課題では、Swing/GUI を使って階層構造を持つ情報を提示します。〈GoF〉Composite/Iterator/Visitor/Command パターンを導入すると、if/for 文によるコードの汚染、配列の境界問題が解消されるので、要求仕様の変更にも柔軟に対処でき、簡潔で見通しの良いコードを記述できるようになります。
《Note》JPython1.1.x/Jython2.1.x 用に作成したセミナー課題を、Jython2.5 で再構成しました。
事例:Java の世界を Jython から観察する
>>> model = Xmodel
>>> model
<TreeComposite.Node object at 0x1>
大域変数 Xmodel を介して、クラス Node のインスタンスを参照できます。
>>> dir(model) ['__class__', '__delattr__', '__dict__', '__doc__', '__getattribute__', '__hash__', '__init__', '__iter__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', 'children', 'node']
この中には、作成したメソッド children/node などが含まれるのが分かります。
Iterator の効能
〈GoF〉Iterator パターンを導入することで広がる、コードの可能性を探ります。
■ for 文との融合
>>> for e in model: print e, type(e) ... colorsblue violet red yellow
モデル model を介して(部分ツリーを構成する)各ノード DefaultMutableTreeNode を順に参照できます。これには、部分ツリーの頂点にある colors も含まれます。
《Note》モデル model を介して、各ノード e を参照したい(what)ときに、それをどのように実現しているか(how)を知る必要はありません。すると、情報隠蔽の原則に沿って、内部構造に依存しない抽象的な表現が可能になります。C言語で採用された、伝統的な for 文との違いはここにあります。
■ 組み込み型 list との融合
>>> list(model)
[colors, blue, violet, red, yellow]
コンストラクター list の引数にモデル model を指定すると(部分ツリーを構成する)各ノードを列挙したリストが得られます。
《Note》前述した for 文と同様に、各ノードを参照する(what)ために内部構造(how)を知る必要はありません。
■ DefaultMutableTreeNode との相違
>>> model.children() [colors, blue, violet, red, yellow] >>> model.node.children() java.util.Vector$1@9bf7f4 >>> list(_) [blue, violet, red, yellow]
モデルが保持するノード model.node から、子ノードを順に参照 children するときには、その頂点にある colors を含みません。
■ ノードの親子関係
>>> model.node colorsJTree >>> parent = _ >>> parent.children() java.util.Vector$1@c88c75 >>> list(_) [colors, sports, food]ノード model.node からその親を参照 parent して、そこから子ノードを順に参照 children すると、その中に頂点 colors を含むのが分かります。■ 組み込み関数 reduce との融合
>>> reduce(lambda s, e: s+1, model, 0) 5 >>> list(model) [colors, blue, violet, red, yellow] >>> len(_) 5
組み込み関数 reduce の第2引数にモデル model を指定すると、各ノードを順に参照するので、その直下にあるノード数が得られます。■ 組み込み関数 map との融合
>>> map(str, model) ['colors', 'blue', 'violet', 'red', 'yellow'] >>> map(lambda e: e.parent, model) [JTree, colors, colors, colors, colors]組み込み関数 map の第2引数にモデル model を指定すると、各ノードを順に参照するので、その直下にあるノードのレベル数 level が得られます。■ 組み込み関数 filter との融合
>>> filter(lambda e: e.leaf, model) [blue, violet, red, yellow] >>> [e for e in model if e.leaf] [blue, violet, red, yellow]組み込み関数 filter の第2引数にモデル model を指定すると、各ノードを順に参照するので、末端にあるノード leaf を列挙したリストが得られます。■ 内包との融合
内包を利用すると、任意の要素を列挙したリストが簡単に得られます。>>> [str(e) for e in model] ['colors', 'blue', 'violet', 'red', 'yellow'] >>> [e.parent for e in model] [JTree, colors, colors, colors, colors]モデル model が保持する部分ツリーの頂点と、その直下にある各ノードの名前(文字列)を列挙したリストが得られます。■ ジェネレーター式との融合
>>> list(e.level for e in model) [1, 2, 2, 2, 2] >>> dict((e, e.level) for e in model) {blue: 2, violet: 2, colors: 1, yellow: 2, red: 2}組み込み関数 map の第2引数にモデル model を指定すると、各ノードを順に参照するので、その直下にあるノードのレベル数 level が得られます。Tips
》作業中です《Last updated♪09/06/09