またまた面白いデザインパターンが登場。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 件のコメント:
コメントを投稿