例題で学ぶデザインパターン #8: テキストによるツリー表示:リファクタリング
例題で学ぶ Jython/Swing デザインパターン《Jython2.5》
テキストによるツリー表示 :リファクタリング
■ 概要
例題により、アプリケーションを作成する過程を通して、Jython/Swing によるデザインパターンを習得します。
この課題では、Swing/GUI を使って階層構造を持つ情報を提示します。〈GoF〉Composite/Iterator/Visitor/Command パターンを導入すると、if/for 文によるコードの汚染、配列の境界問題が解消されるので、要求仕様の変更にも柔軟に対処でき、簡潔で見通しの良いコードを記述できるようになります。
《Note》JPython1.1.x/Jython2.1.x 用に作成したセミナー課題を、Jython2.5 で再構成しました。
事例:モジュールを起動する
モジュールを起動すると、次のようなウィンドウが現れます。
$ jython2.5b3 -i step07/TreeEx.py
リファクタリングによって、なにも影響を受けないことが確認できます。
事例:Java の世界を Jython から観察する
実行中の Java アプリケーションの状態を、Jython の対話モードで確認できるので、とても便利です。
$ jython2.5b3 -i step05/TreeEx.py >>> model = Xmodel >>> list(model) [colors, blue, violet, red, yellow] >>> len(model) Traceback (most recent call last): File "", line 1, in TypeError: len() of unsized object
これまでは、組み込み関数 len に呼応して、例外 TypeError を生成していました。
$ jython2.5b3 -i step07/TreeEx.py >>> model = Xmodel >>> list(model) [colors, blue, violet, red, yellow] >>> len(model) 4
これからは、組み込み関数 len に呼応して、子ノードの数が得られます。
事例:コードの解説
#! /usr/bin/jython2.5b3 class Node(object): def __init__(self, node, *args, **keys): self.node = nodeself.level = level
リファクタリングによって、以前に導入したインスタンス属性 self.level が、不要になります。
def __str__(self): return "\n".join([ "%s%s%s"%( "| "*(level-1), "+-- "*(not not level), node, ) for node, level in zip(self.children(), self.levels()) ])
組み込み関数 zip を使うと、リファクタリングによって要素分解したメソッド children/levels を、自由に組み合わせて利用できます。
def __len__(self): return reduce( lambda s, e: s + len(Node(e)) + 1, self.node.children(), # (@.@) 0)
特殊メソッド __len__ は、組み込み関数 len に呼応して、子ノードの数を獲得します。
def children(self): return reduce( lambda s, e: s + Node(e).children(), self.node.children(), # (@.@) [self.node]) def levels(self, level=0): return reduce( lambda s, e: s + Node(e).levels(level+1), self.node.children(), # (@.@) [level])
前述した children では、コンストラクター Node に引数(レベルを表現する)を指定する必要がありました。今回は、リファクタリングにより、2つのメソッド children/levels に要素分解したので、簡潔で見通しの良いコードになります。
■ 何が問題か
リファクタリングにより、複数のメソッドに要素分解したので、コードは簡潔になりました。しかし、メソッドの数が増え、同じコードの断片 (@.@) が散在しています。
Tips
》作業中です《