《付録》dirComposite.py

# -*- coding: utf-8 -*-
#===============================================================================
#    Copyright (C) 2000-2008, 小泉ひよ子とタマゴ倶楽部
#
# Change History: WPF examples
#    2008/01/25, IronPython 1.1.1 (download)
#    2008/08/22, IronPython 1.1.2 (download)
#    2008/03/16, ver.2.0, WPF
#    2008/00/00, ver.2.1, IronPython 1.1.2 
#===============================================================================
from _ant import *
from System.IO import *
from System.Windows import *
from System.Windows.Controls import *

clr.AddReference("System.Windows.Forms")
from              System.Windows.Forms import OpenFileDialog
from nt import listdir

## --------------------                # Composite::Component            
class FileSystem:
    def __init__(self, name=None):
        self.name = name
        self.size = 0
        self.items = 

    def total(self):
        return reduce(
            lambda acc, e: acc + e.total(),
            self.items,
            self.size)

    def changed(self, client):        
        client.update(
            self.branch(self, 0),
            "%d bytes"%self.total())

    def branch(self, parent, indent):
        s = 
        for child in parent.items:
            s.append("%s+-- %s"%(" "*4*indent, child.name))
            if self._isdir(child):
                s.append(" [%d]\n"%child.total())
                s.append(self.branch(child, indent+1))
            else:
                s.append(" [%d]\n"%child.size)
        return "".join(s)

    def _isdir(self, node):
        return len(node.items)

## --------------------                # Composite::Client            
class TreeBuilder:
    def __init__(self, root, path):
        self.clearNode(root)
        parent = FileSystem(self._tail(path))
        self.addNode(root, parent)
        self.branch(parent, path, 0)

    def _tail(self, path):
        return path.split("\\")[-1]
    
    def clearNode(self, parent):
        parent.items.Clear()
    
    def addNode(self, parent, child):
        parent.items.Add(child)

    def branch(self, parent, path, indent):
        dirs = listdir(path); dirs.sort()    
        for e in dirs:
            child = FileSystem(e)
            self.addNode(parent, child)
            info = FileInfo("%s\%s"%(path, e))
            if self._isdir(info):
                self.branch(child, "%s\%s"%(path, e), indent+1)
            else:
                child.size = info.Length
            
    def _isdir(self, info):
        return str(FileAttributes.Directory) in str(info.Attributes)

## --------------------               
class ExWindow(Window):
    def __init__(self, Content=None, **args):
        self.InitializeComponent(Content)
        self.init()

    def InitializeComponent(self, Content):
        self.Content = LoadXaml(Content)
        
    def init(self):
        target = "button", "textView", "total",
        self._Controls(target)

        self.button.Click += self.click
        self.root = FileSystem()
        self.update("(^.^)", "0 byte")

    def _Controls(self, target):
        controls = xaml_controls(self)
        for e in target:
            setattr(self, e, controls[e])

    def click(self, sender, e):
        dialog = OpenFileDialog()
        dialog.ShowDialog()
        TreeBuilder(
            self.root,
            FileInfo(dialog.FileName).Directory.FullName)
        self.root.changed(self)

    def update(self, text, value):
        self.textView.Text = text
        self.total.Content = value

## --------------------               
if __name__ == "__main__":
    xaml = __file__.replace(".py",".xaml")
    win = ExWindow(
        Title=__file__,
        Width=240, Height=200,
        Content=xaml,
        )
    Application().Run(win)

## --------------------               

第1章 Composite パターン 2/5

記事一覧 C#.use(better, IronPython=”WPF”)《IronPython2.6》
# IronPython で学ぶ WPF プログラミングの世界

Composite パターン

《著》本間りす+小粒ちゃん《監修》小泉ひよ子とタマゴ倶楽部
第3版♪2008/04/28

Composite パターンには、いくつの効能があります。ここでは、if/else に象徴される典型的なハードコーディングの問題点を回避するとともに、動的な問題解決が可能になる事例を紹介します。

木構造ファイルシステムの表現

木構造を使って、ファイルシステムを表現する方法を紹介します。

class ExWindow(Window):
    def init(self):
        target = "button", "textView", "total",
        self._Controls(target)

        self.button.Click += self.click
        self.root = FileSystem()
        self.update("(^.^)", "0 byte")

ボタン self.button をクリックすると、イベントハンドラー self.click を起動して、新たな木構造を築きます。そのツリーの頂点 self.root には、FileSystem が配置されます。ツリーを描くテキスト領域 self.textView と、フォルダーに含まれるファイルの合計サイズを示すラベル self.total には、初期値が表示 self.update されます。

    def click(self, sender, e):
        dialog = OpenFileDialog()
        dialog.ShowDialog()
        TreeBuilder(
            self.root,
            FileInfo(dialog.FileName).Directory.FullName)
        self.root.changed(self)

TreeBuilder によって生成される、新たなツリーの頂点 self.root には、選択したファイル dialog.FileName を含むフォルダーが設定されます。self.root を頂点とするツリー情報をもとに、テキスト領域とラベルを更新 changed します。

1)対象となる集合体:Client

Composite::Client では、Composite::Component で規定されたプロトコルに従う、各コントロールを配置します。

## --------------------                # Composite::Client            
class TreeBuilder:
    def __init__(self, root, path):
        self.clearNode(root)
        parent = FileSystem(self._tail(path))
        self.addNode(root, parent)
        self.branch(parent, path, 0)

選択したファイルを含むフォルダーを頂点とする、木構造を築きます。まず、指定したフォルダー path に相当する、新たな部分木 parent を用意します。次に、頂点 root の傘下に、部分木 parent を追加 addNode します。そして、parent を頂点とする新たな部分木を、フォルダー path の情報に基づいて築き branch ます。

    def branch(self, parent, path, indent):
        dirs = listdir(path); dirs.sort()    
        for e in dirs:
            child = FileSystem(e)
            self.addNode(parent, child)
            info = FileInfo("%s\%s"%(path, e))
            if self._isdir(info):
                self.branch(child, "%s\%s"%(path, e), indent+1)
            else:
                child.size = info.Length

parent を頂点とする新たな部分木を、フォルダー path の情報に基づいて築きます。メソッド nt.listdir を利用すると、フォルダーの直下にある各項目(フォルダー/ファイル)を列挙したリスト dirs が得られます。
まず、各項目 e(フォルダー/ファイル)に相当する、新たな部分木 child を用意します。次に、頂点 parent の傘下に、部分木 child を追加 addNode します。そして、その項目 e がフォルダーなら、それを頂点とする新たな部分木を生成 branch します。その項目 e がファイルなら、そのサイズ info.Length を設定します。

《Note》楽をするための努力を惜しまない:Composite::Client の役割のひとつが、OOPフレームワークを提供することです。ここで、if/else が必須となるのは、OOPフレームワークを持たない外界との境界に位置して、新たなフレームワークを構築する必要があるからです。すると、境界内では、OOP の恩恵が受けられるので、冗長な if/else が不要になり、簡潔で見通しの良いコードを記述できるだけでなく、動的な問題解決が可能になります。つまり、ここで楽をするための努力を惜しまなければ、後で楽ができるというわけです。(^_^) □

》こちらに移動中です《
TOP


関連記事

Last updated♪2009/11/20