例題で学ぶデザインパターン #8: テキストによるツリー表示:リファクタリング

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

例題で学ぶ Jython/Swing デザインパターン《Jython2.5》
テキストによるツリー表示 リファクタリング

《著》越智ことり+小粒ちゃん《監修》小泉ひよ子とタマゴ倶楽部
第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 で再構成しました。

事例:モジュールを起動する

モジュールを起動すると、次のようなウィンドウが現れます。

$ 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 = node
        self.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

》作業中です《

Last updated♪09/06/10