2010年11月23日火曜日

第12章 Decoratorパターン : 飾り枠と中身の同一視 ~ design patterns with python ~



Decoratorパターンは前回のCompositeパターン
http://ksk77.blogspot.com/2010/11/11-composite.html
と同様、同一視がキーワードですね。

DecoratorパターンのUML(Fig 12-5 p.179)を見てみると、CompositeパターンのUML(Fig 11-3 p.164)とよく似ているのが分かります。
それもそのはずで、前回のファイルシステムの例で考えて見れば、ディレクトリを『飾り枠』としても同様の構造を記述できることが想像できます。またCompositeでは末端(Leaf)が分離され、Decoratorでは根っこ(ConcreteComponent)が分離されています。

Decoratorパターンは、言うなれば、中身が常に一つで、追加や取り出しが出来ないCompositeパターンでしょうか。…普通そんな風には考えないと思いますが。

Decoratorパターンの特徴は、どこを切ってもそこにはただ一つのComponentがあるという点でしょう。マトリョーシカのように。

--

SideBorderクラスのコンストラクタは引数の順番が逆な方が分かりやすいと思います。
あと今回は書籍内のコードを読まずに書いたので、実装が書籍に沿わないかもです。


実行結果
Hello, world.
#Hello, world.#
+---------------+
|#Hello, world.#|
+---------------+
/+----------------+/
/|+--------------+|/
/||*+----------+*||/
/||*|konnichiwa|*||/
/||*+----------+*||/
/|+--------------+|/
/+----------------+/

ソースコード
#!/usr/bin/env python
# -*- coding: utf8 -*-

class Display:
    def __init__(self): raise Exception("Abstract class")
    def columns(self): raise NotImplementedError
    def rows(self): raise NotImplementedError
    def rowText(self, index): raise NotImplementedError
    def show(self):
        for i in xrange(self.rows()):
            print self.rowText(i)

class StringDisplay(Display):
    def __init__(self, string):
        self.__string = string

    def columns(self):
        return len(self.__string)

    def rows(self):
        return 1

    def rowText(self, index):
        return self.__string


class Border(Display):
    _display = None


class SideBorder(Border):
    def __init__(self, borderChar, display):
        self.__borderChar = borderChar
        self._display = display

    def columns(self):
        return self._display.columns() + 2

    def rows(self):
        return self._display.rows()

    def rowText(self, index):
        return self.__borderChar + self._display.rowText(index) + self.__borderChar


class FullBorder(Border):
    def __init__(self, display):
        self._display = display

    def columns(self):
        return self._display.columns() + 2

    def rows(self):
        return self._display.rows() + 2

    def rowText(self, index):
        if index == 0 or index == self.rows()-1:
            return "+" + "".join(["-" for i in xrange(self._display.columns())]) + "+"
        else:
            return "|" + self._display.rowText(index-1) + "|"



def main():
    # these data type are Display
    m_b1 = StringDisplay("Hello, world.")
    m_b2 = SideBorder("#", m_b1)
    m_b3 = FullBorder(m_b2)
    m_b4 = SideBorder("/", FullBorder(FullBorder(SideBorder("*", FullBorder(StringDisplay("konnichiwa"))))))
    m_b1.show()
    m_b2.show()
    m_b3.show()
    m_b4.show()

if __name__=='__main__': main()

0 件のコメント:

コメントを投稿