《Jython2.5》JTree〈GoF〉Visitor を実現する

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

Java プログラマーのための Python 導入ガイド〈初級/応用編〉《Jython2.5》
JTree〈GoF〉Visitor を実現する

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

■ 概要

フォルダー/ファイルの階層構造を Swing/GUI を利用して「簡単に」閲覧できるツールがあると便利です。

 この課題では、Swing/GUI を使って階層構造を持つ情報を提示します。
 また〈GoF〉Composite/Iterator/Visitor/Command パターンを導入することで、
 構造化プログラミングには必須の if/for が不要になるので、簡潔で見通しが良く、
 要求仕様の変更にも柔軟に対処できる、プログラム(コード)を作成する方法を紹介します。

 《Note》JPython1.1.x/Jython2.1.x 用に作成したセミナー課題を、Jython2.5 で再構成しました。

事例:コードの解説

GoF を反面教師に…
class Node(object):                         # Composite::Component
    def accept(self, visitor, arg=0):
        eval("visitor.visit%s(self, arg)"%self.__class__.__name__)

GoF の記述を鵜呑みにすると、損をします。Smalltalk と同様に、メタプログラミングを活用して、クラス名をもとに「動的に」メソッド呼び出しを行う仕組みを導入するなら、子孫クラスで個別の accept を定義する必要はありません。

今回の例題では、高々2つのクラスしか登場しませんが、実際のアプリケーション開発では、多数のクラスを対象するのが常です。なにより、要求仕様の変更の度に、新たな accept を定義する必要がなくなるので、より本質的な問題解決に専念できるようになります。
⇒ 続きはこちら GoF を反面教師に

■ テキストによる表示:シーケンス処理を基調に

選択したノードの傘下を、テキスト(JTextArea)で表現します。

class TextVisitor(Visitor):
    def __init__(self):
        self.tree = []
    def __str__(self):
        return "\n".join(self.tree)

インスタンス属性 self.tree には、Visitor によって得られた情報を累積します。

    def visitFileNode(self, node, indent):
        self.tree += ["%s%s%r (%d)"%(
            self.tab1*(indent-1), self.tab2, node, node.getsize())]

各ファイル node では、インデント(深さ)indent に相当するタブに続いて、node の名前とサイズ getsize() を表示します。

    def visitDirNode(self, node, indent):
        self.tree += ["%s%s%r"%(
            self.tab1*(indent-1), self.tab2*(not not indent), node)]

各フォルダー node では、ツリーの枝(branch)に位置するので、インデント(深さ)indent に相当するタブに続いて、node の名前を表示します。

■ ツリーによる表示:再帰的な構造に沿って

選択したノードの傘下を、ツリー(JTree)で表現します。

class TreeVisitor(Visitor):
    def visitFileNode(self, node, parent):
        pass

ファイル node は、ツリーの末端(leaf)に位置するので、何もしません。つまり、このメソッドが、再帰呼び出しの「停止条件」に相当します。

    def visitDirNode(self, node, parent):
        for e in node.treeNode.children():
            current = e.userObject
            child = DefaultMutableTreeNode(current)
            parent.add(child)
            current.accept(TreeVisitor(), child)

フォルダー node は、ツリーの枝(branch)に位置するので、その子 treeNode.children() をたどる必要があります。その子 current に対して、さらに accept を適用することで、再帰的な構造にもうまく対処できます。

current は、ファイル/フォルダーのどちらかの可能性がありますが、それは実行時に確定するので、その処理を TreeVisitor に委ねます。すると(構造化プログラミングを象徴する)if による条件分岐が不要になるので、簡潔で見通しの良いコードを記述できるようになります。

Tips

》作業中です《

Last updated♪09/05/23