例題で学ぶデザインパターン #6: Iterator の効能

前の記事記事一覧次の記事

例題で学ぶ Jython/Swing デザインパターン《Jython2.5》
Iterator の効能

《著》越智ことり+小粒ちゃん《監修》小泉ひよ子とタマゴ倶楽部
第1版♪2003/05/23 ● 第2版♪2009/04/03

■ 概要

例題により、アプリケーションを作成する過程を通して、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 の効能

GoFIterator パターンを導入することで広がる、コードの可能性を探ります。

■ for 文との融合
>>> for e in model: print e, type(e)
... 
colors 
blue 
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
colors
    
JTree >>> 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