《Jython2.5》JTree〈GoF〉Iterator が必要に

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

Java プログラマーのための Python 導入ガイド〈初級/応用編〉《Jython2.5》
JTree〈GoFIterator が必要に

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

■ 概要

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

この課題では、Swing/GUI を使って階層構造を持つ情報を提示します。〈GoF〉Composite/Iterator/Visitor/Command パターンを導入すると、if/for 文によるコードの汚染、配列の境界問題が解消されるので、要求仕様の変更にも柔軟に対処でき、簡潔で見通しの良いコードを記述できるようになります。

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

事例:コードの解説

次に示すコードの断片はみな、それを実現する手段(how)に依存しています。これを改善して、それで実現したい目的(what)に着目したコードを記述できるようにします。

■ ファイル(フォルダー内)の数
class FileNode(Node):                           # Composite::Leaf
    def __len__(self):
        return 0

class DirNode(Node):                            # Composite::Composite
    def __len__(self):
        return reduce(
            lambda s,e: s+len(e.userObject)+1,
            self.treeNode.children(),
            0)
■ ファイル(フォルダー内)の合計サイズ
class FileNode(Node):                           # Composite::Leaf
    def getsize(self):
        return getsize(self.path)

class DirNode(Node):                            # Composite::Composite
    def getsize(self):
        return reduce(
            lambda s,e: s+e.userObject.getsize(),
            self.treeNode.children(),
            0)
■ インデント数(ノードの深さ)

メソッド indents を利用すると、各ノードのインデントを返すイテレーターが得られます。

class FileNode(Node):                           # Composite::Leaf
    def indents(self, indent=0):
        return [indent]

class DirNode(Node):                            # Composite::Composite
    def indents(self, indent=0):
        return reduce(
            lambda s,e: s+e.userObject.indents(indent+1),
            self.treeNode.children(),
            [indent])

メソッド indents の本体でも、同様に view/DefaultMutableTreeNode と model/Node との相互参照が必要になります。

■ ツリー表示:JTextArea
class FileNode(Node):                           # Composite::Leaf
    def textTree(self, indent=0):
        return ["%s%s%r (%d)"%(
            self.tab1*(indent-1), self.tab2, self, self.getsize())]

class DirNode(Node):                            # Composite::Composite
    def textTree(self, indent=0):
        return reduce(
            lambda s,e: s+(e.userObject.textTree(indent+1)),
            self.treeNode.children(),
            ["%s%s%r"%(
                self.tab1*(indent-1), self.tab2*(not not indent), self)])
■ 前順走査
class FileNode(Node):                           # Composite::Leaf
    def preorder(self):
        return [self]

class DirNode(Node):                            # Composite::Composite
    def preorder(self):
        return reduce(
            lambda s,e: s+e.userObject.preorder(),
            self.treeNode.children(),
            [self])

メソッド preorder の本体では、ビュー DefaultMutableTreeNode から得られる子ノード treeNode.children の情報をもとに、各ノードから e.userObject よって、再びモデル Node を参照しています。

何が問題か

これらの事例は「copy&paste の弊害」と同じ病巣を抱えています。このセミナー課題では、5つの場合を挙げていますが、実際のアプリケーション開発では、数多の場合に対処する必要が生じます。このアプローチを踏襲するかぎり「数多の似て非なるコードを書く」という呪縛を解く術がありません。

■ オブジェクトの抽象化:情報隠蔽の原則

DefaultMutableTreeNode に依存する部分が多いと、簡潔で見通しの良いコードを記述できないだけでなく、要求仕様の変更にも柔軟に対処できません。そのため、それを実現する手段を変更(たとえば、他のコンポーネントを利用)するたびに、それに依存するコードをすべて再構成する必要に迫られます。

オブジェクト指向プログラミングでは「抽象化」を支援するメカニズムを利用すると、特定の実現方法に依存した「条件反復」を排除できるので、構造化プログラミングの定石である「for 文」によってコードが汚染されるのを防げます。

⇒ 続きはこちら コードの解説

Tips

》作業中です《

Last updated♪09/05/27