今回はAbstract Factoryパターン。このデザインパターンはこれまでのパターンの応用という位置づけになっている(と思う)。とはいえ、やっていることは第4章のFactory Method(http://ksk77.blogspot.com/2010/11/4-factory-method.html)の拡張で、
- Productを複数個に増やし、
- それらを(抽象)部品として扱い、
- factoryMethod()をその(抽象)部品から組み立てた(抽象)製品を作るメソッドに置き換える
と考えると分かりやすい。この『部品から製品を』というところで、前章のBuilderパターンhttp://ksk77.blogspot.com/2010/11/7-builder-with-python.htmlの経験が生きてくるのかこないのか、といった感じ。
今回のデザインパターンで強く意識させられたのは、デザインパターンの大きなメリットの一つである
- 依存しない/既存のソースコードを一切変更しない
というところ。練習問題で、これが効率・生産性・心理的にどれだけ意味があるかを実感しました。
あと、内包表記様様って感じです。
ソースコード
factory.py
# -*- coding: utf8 -*-
class Factory:
@classmethod
def getFactory(cls, classname):
def get_class( kls ):
parts = kls.split('.')
module = ".".join(parts[:-1])
m = __import__( module )
for comp in parts[1:]:
m = getattr(m, comp)
return m
try:
C = get_class(classname)
return C()
except:
print "invalid classname -> %s" % (classname)
raise Exception()
def createLink(self, caption, url): raise NotImplementedError
def createTray(self, caption): raise NotImplementedError
def createPage(self, title, author): raise NotImplementedError
class Item:
def makeHTML(self): raise NotImplementedError
class Link(Item):
def __init__(self, caption, url):
self.caption = caption
self.url = url
class Tray(Item):
def __init__(self, caption):
self.caption = caption
self.tray = []
def add(self, item): self.tray.append(item)
class Page:
def __init__(self, title, author):
self.title = title
self.author = author
self.contents = []
def add(self, item): self.contents.append(item)
def output(self): print self.makeHTML()
def makeHTML(self): raise NotImplementedError
listfactory.py
# -*- coding: utf8 -*-
from factory import Factory, Link, Tray, Page
class ListFactory(Factory):
def createLink(self, caption, url): return ListLink(caption, url)
def createTray(self, caption): return ListTray(caption)
def createPage(self, title, author): return ListPage(title, author)
class ListLink(Link):
def makeHTML(self): return '<li><a href="%s">%s</a></li>' % (self.url, self.caption)
class ListTray(Tray):
def makeHTML(self): return '<li>%s<ul>%s</ul></li>' % (self.caption, ''.join([i.makeHTML() for i in self.tray]))
class ListPage(Page):
def makeHTML(self): return '<html><head><title>%s</title></head><body><ul>%s</ul><hr><address>%s</address></hr></body></html>' % (self.title, ''.join([i.makeHTML() for i in self.contents]), self.author,)
tablefactory.py
# -*- coding: utf8 -*-
from factory import Factory, Link, Tray, Page
class TableFactory(Factory):
def createLink(self, caption, url): return TableLink(caption, url)
def createTray(self, caption): return TableTray(caption)
def createPage(self, title, author): return TablePage(title, author)
class TableLink(Link):
def makeHTML(self): return '<td><a href="%s">%s</a></td>' % (self.url, self.caption)
class TableTray(Tray):
def makeHTML(self): return '<td><table border="1" width="100%%"><tr><th colspan="%d">%s</th></tr><tr>%s</tr></table></td>' % (len(self.tray), self.caption, ''.join([i.makeHTML() for i in self.tray]))
class TablePage(Page):
def makeHTML(self): return '<html><head><title>%s</title></head><body><table border="3"><tbody>%s</tbody></table><hr><address>%s</address></hr></body></html>' % (self.title, ''.join(['<tr>'+i.makeHTML()+'</tr>' for i in self.contents]), self.author,)
main.py
#!/usr/bin/env python
# -*- coding: utf8 -*-
from factory import Factory
import sys
def main():
try:
factory = Factory.getFactory(sys.argv[1])
except:
print "Usage: python main.py class.name.of.ConcreteFactory"
print "Example 1: python main.py listfactory.ListFactory"
print "Example 2: python main.py tablefactory.TableFactory"
sys.exit(0)
asahi = factory.createLink("朝日新聞", "http://www.asahi.com/") # Link's instance
yomiuri = factory.createLink("読売新聞", "http://www.yomiuri.co.jp/") # Link's instance
us_yahoo = factory.createLink("Yahoo!", "http://www.yahoo.com/") # Link's instance
jp_yahoo = factory.createLink("Yahoo!Japan", "http://www.yahoo.co.jp/") # Link's instance
excite = factory.createLink("Excite", "http://www.excite.com/") # Link's instance
google = factory.createLink("Google", "http://www.google.com/") # Link's instance
traynews = factory.createTray("新聞") # Tray's instance
traynews.add(asahi)
traynews.add(yomiuri)
trayyahoo = factory.createTray("Yahoo!") # Tray's instance
trayyahoo.add(us_yahoo)
trayyahoo.add(jp_yahoo)
traysearch = factory.createTray("サーチエンジン") # Tray's instance
traysearch.add(trayyahoo)
traysearch.add(excite)
traysearch.add(google)
page = factory.createPage("LinkPage", "結城 浩") # Page's instance
page.add(traynews)
page.add(traysearch)
page.output()
if __name__=="__main__": main()
0 件のコメント:
コメントを投稿