今回は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 件のコメント:
コメントを投稿