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

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

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

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

事例:コードの解説

class View(JPanel):
    def init_buttons(self):
        panel = JPanel()
        panel.layout = BoxLayout(panel, BoxLayout.LINE_AXIS)

        from TreeCommand import TextCommand
        self.textButton = CommandButton(
            label = "Text",
            actionPerformed = self.actionPerformed,
            command = TextCommand(self),
            )
        from TreeCommand import TreeCommand
        self.treeButton = CommandButton(
            label = "Tree",
            actionPerformed = self.actionPerformed,
            command = TreeCommand(self),            
            )
        for e in [
            self.textButton,
            self.treeButton,
        ]:
            panel.add(e)
        return panel

    def actionPerformed(self, e):
        e.source.command()

⇔ 承前 何が問題だった のか
メソッド actionPerformed の本体では、if 文が不要になるので、簡潔で見通しの良いコードを記述できるだけでなく、要求仕様の変更にも柔軟に対処できるようになります。属性 .command は、呼び出し可能オブジェクト(TextCommand/TreeCommand)を参照するので、演算子 () に呼応して、メソッド __call__ の本体に記述したコードの断片を実行します。

■ 拡張可能なコンポーネント
class CommandButton(JButton): pass

既存の Swing コンポーネントには、新たな属性を追加できません。そこで、子孫クラス CommandButton を用意して、新たな属性を追加できるようにします。ただし、クラスを介在させることだけに意味があるので、その本体は空 pass にします。

■ 呼び出し可能オブジェクト:__call__

メソッド __call__ は、演算子 () に呼応して、呼び出し可能オブジェクトの動作を規定します。

class Command:                              # Command::Command
    def __init__(self, view):
        self.view = view
    def __call__(self):
        raise NotImplementedError, self.__class__.__name__

子孫クラスでメソッド __call__ を実現しないと、実行時に例外 NotImplementedError を生成することで、プログラマーへの注意を促します。

■ 事例:テキスト表示
class TextCommand(Command):                 # Command::ConcreteCommand
    def __call__(self):
        current = self.view.currentObject
        if not current: return
        
        visitor = TextVisitor()
        for e, indent in zip(current, current.indents()):
            e.accept(visitor, indent)
        view = JTextArea(
            text = str(visitor),
            font = Font("Courier", Font.PLAIN, 12),
            )
        from TreeView import PopWindow
        win = PopWindow(
            title = repr(current),
            )
        win.contentPane.add(JScrollPane(view))
        win.open(900, 200, 300, 200)
■ 事例:ツリー表示
class TreeCommand(Command):                 # Command::ConcreteCommand
    def __call__(self):
        current = self.view.currentObject
        if not current: return

        root = DefaultMutableTreeNode(current)
        current.accept(TreeVisitor(), root)

        view = JTree(root)
        from TreeView import PopWindow
        win = PopWindow(
            title = repr(current),
            )
        win.contentPane.add(JScrollPane(view))
        win.open(900, 200, 300, 200)

Tips

》作業中です《

Last updated♪09/05/20