2010年11月20日土曜日

第9章 Bridgeパターン : 機能の階層と実装の階層を分ける [デザインパターン with python]



またまた面白いデザインパターンが登場。Bridgeパターンでは

  • 機能のクラス階層
  • 実装のクラス階層

という単語がしばしば登場する。本を読み、演習を解けば、この違いははっきりと分かるようになるし、これらを分ける理由も理解できる。

大事なことは、そもそもプログラミングするときに、

  • 機能を書く ― 実装を書く

という発想がなく、単に

  • これはクラスだからextends
  • これはインターフェイスだからimplements

くらいしか考えてなかったことだろう。
(機能―実装 と クラス―インターフェイス とを対比させるのは明らかにおかしいけど)
機能/実装という見方でコードを読んだり書いたりすると、プログラマとして一歩前進できそうだ。

実装のクラス階層をOS依存で考える例や、継承と委譲の考え方の対比なんかも勉強になりました。


実行結果
+-------------+
|Hello, Japan.|
+-------------+
+----------------+
|Hello, Universe.|
+----------------+
+----------------+
|Hello, Universe.|
|Hello, Universe.|
|Hello, Universe.|
|Hello, Universe.|
|Hello, Universe.|
+----------------+
+----------------------------------+
|How many times have I been called?|
|How many times have I been called?|
|How many times have I been called?|
|How many times have I been called?|
+----------------------------------+
この味は

うそをついてる味なんだなあ 



みつを 

< >
< * >
< * * >
< * * * >
| -
| ## -
| ## ## -
| ## ## ## -
| ## ## ## ## -
| ## ## ## ## ## -

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

# 機能のクラス階層

class Display:
    def __init__(self, impl): self.impl = impl
    def prepare(self): self.impl.rawPrepare()
    def draw(self): self.impl.rawDraw()
    def finish(self): self.impl.rawFinish()
    def display(self):
        self.prepare()
        self.draw()
        self.finish()

class CountDisplay(Display):
    def multiDisplay(self, times):
        self.prepare()
        for i in xrange(times): self.draw()
        self.finish()

#9-1
from random import randint
class RandomDisplay(CountDisplay):
    def randomDisplay(self, max_times): self.multiDisplay(randint(0,max_times-1))

#9-3
class IncreaseDisplay(CountDisplay):
    def increaseDisplay(self, times):
        for i in xrange(times): self.multiDisplay(i)


# 実装のクラス階層

class DisplayImpl:
    def __init__(self): raise Exception("Abstract class")
    def rawPrepare(self): raise NotImplementedError
    def rawDraw(self): raise NotImplementedError
    def rawFinish(self): raise NotImplementedError

class StringDisplayImpl(DisplayImpl):
    def __init__(self, string): self.string = string
    def rawPrepare(self): self.__printLine()
    def rawDraw(self): print "|%s|" % self.string
    def rawFinish(self): self.__printLine()
    def __printLine(self): print '+%s+' % ''.join(['-' for i in xrange(len(self.string))])

#9-2
class FileDisplayImpl(DisplayImpl):
    import sys
    def __init__(self, filename):
        self.filename = filename
        self.fileobj = None
    def rawPrepare(self):
        try:
            self.fileobj = open(self.filename, 'r')
        except IOError, (errno, strerror):
            print "I/O error(%s): %s" % (errno, strerror)
            sys.exit(0)
    def rawDraw(self):
        self.fileobj.seek(0) # reset
        for line in self.fileobj: print line
    def rawFinish(self): self.fileobj.close()

#9-3
class CharDisplayImpl(DisplayImpl):
    def __init__(self, head, body, foot):
        self.head = head
        self.body = body
        self.foot = foot
    def rawPrepare(self): print self.head,
    def rawDraw(self): print self.body,
    def rawFinish(self): print self.foot



def main():
    d1 = Display(StringDisplayImpl('Hello, Japan.'))
    d2 = CountDisplay(StringDisplayImpl('Hello, Universe.'))
    d1.display()
    d2.display()
    d2.multiDisplay(5)

    #9-1
    d3 = RandomDisplay(StringDisplayImpl('How many times have I been called?'))
    d3.randomDisplay(5)

    #9-2
    d4 = CountDisplay(FileDisplayImpl('mitsuo.txt'))
    d4.multiDisplay(1)

    #9-3
    d5 = IncreaseDisplay(CharDisplayImpl('<','*','>'))
    d5.increaseDisplay(4)
    d6 = IncreaseDisplay(CharDisplayImpl('|','##','-'))
    d6.increaseDisplay(6)

if __name__=='__main__': main()

0 件のコメント:

コメントを投稿