As a material for learning GoF design patterns, the book "Introduction to Design Patterns Learned in the Augmented and Revised Java Language" seems to be helpful. However, since the examples taken up are based on JAVA, I tried the same practice in Python to deepen my understanding.
The Abstract Factory pattern is one of the design patterns defined by GoF (Gang of Four; 4 gangs). The purpose is to streamline the reuse of multiple modules by aggregating the APIs for generating related instances. In Japanese, it is often translated as "abstract factory". Also called Kit pattern
UML class and sequence diagram UML class diagram (The above is quoted from Wikipedia)
The Abstract Factory pattern seems to make an abstract product by combining abstract parts from ** abstract factory **. In fact, I would like to run the Python implementation code of the Abstract Factory and understand the image of the ** abstract factory **. The sample program taken up here creates a collection of links with a hierarchical structure as an HTML file.
--When operated in ListFactory
mode, an HTML file of list-format links will be generated.
--When operated in TableFactory
mode, an HTML file of table-format links is generated.
First, let's run the code that creates the ** Link-based ** web page.
$ python Main.py ListFactory
[LinkPage.html] was created.
A file called LinkPage.html
has been generated.
When I checked the appearance with a web browser, it looked like this.
Next, let's run the code that creates a ** Table-based ** web page.
$ python Main.py TableFactory
[LinkPage.html] was created.
A file called LinkPage.html
has been generated.
When I checked the appearance with a web browser, it looked like this.
Similar code has been uploaded to the Git repository. https://github.com/ttsubo/study_of_design_pattern/tree/master/AbstractFactory
--Directory structure
.
├── Main.py
└── factory
├── __init__.py
├── factory.py
├── listfactory
│ ├── __init__.py
│ └── list_factory.py
└── tablefactory
├── __init__.py
└── table_factory.py
The ʻAbstractProduct role defines the interface of the abstract parts and products created by the ʻAbstractFactory
role. In the sample program, the Link
class, Tray
class, and Page
class serve this role.
factory/factory.py
import sys
from abc import ABCMeta, abstractmethod
... (snip)
class Item(metaclass=ABCMeta):
def __init__(self, caption):
self.caption = caption
@abstractmethod
def makeHtml(self):
pass
class Link(Item, metaclass=ABCMeta):
def __init__(self, caption, url):
super().__init__(caption)
self.url = url
class Tray(Item, metaclass=ABCMeta):
def __init__(self, caption):
super().__init__(caption)
self.tray = []
def add(self, item):
self.tray.append(item)
class Page(metaclass=ABCMeta):
def __init__(self, title, author):
self.title = title
self.author = author
self.content = []
def add(self, item):
self.content.append(item)
def output(self):
try:
filename = self.title + '.html'
writer = open(filename, 'w')
writer.write(self.makeHtml())
writer.close()
print("[" + filename + "]" + " was created.")
except Exception as e:
print(e)
sys.exit(1)
@abstractmethod
def makeHtml(self):
pass
The ʻAbstractFactory role defines the interface for creating an instance of the ʻAbstractProduct
role.
In the sample program, the Factory
class serves this role.
factory/factory.py
import sys
from abc import ABCMeta, abstractmethod
class Factory(metaclass=ABCMeta):
@abstractmethod
def createLink(self, caption, url):
pass
@abstractmethod
def createTray(self, caption):
pass
@abstractmethod
def createPage(self, title, author):
pass
... (snip)
The Client
role does its job using only the interfaces of the ʻAbstractFactory and ʻAbstractProduct
roles.
The Client
role does not know about specific parts, products or factories. In the sample program, the startMain
method serves this role.
Main.py
import sys
import inspect
import factory
def startMain(factoryObject):
asahi = factoryObject.createLink("Asahi", "http://www.asahi.com")
yomiuri = factoryObject.createLink("Yomiuri", "http://www.yomiuri.co.jp")
us_yahoo = factoryObject.createLink("Yahoo", "http://www.yahoo.com")
jp_yahoo = factoryObject.createLink("Yahoo!Japan", "http://www.yahoo.co.jp")
google = factoryObject.createLink("Google", "http://www.google.com")
excite = factoryObject.createLink("Excite", "http://www.excite.co.jp")
traynews = factoryObject.createTray("Newspaper")
traynews.add(asahi)
traynews.add(yomiuri)
trayyahoo = factoryObject.createTray("Yahoo!")
trayyahoo.add(us_yahoo)
trayyahoo.add(jp_yahoo)
traysearch = factoryObject.createTray("Search Engine")
traysearch.add(trayyahoo)
traysearch.add(excite)
traysearch.add(google)
page = factoryObject.createPage("LinkPage", "Hiroshi Yuki")
page.add(traynews)
page.add(traysearch)
page.output()
if __name__ == '__main__':
for _, plugin in inspect.getmembers(factory, inspect.isclass):
if plugin.__name__ == sys.argv[1]:
startMain(plugin())
The ConcreteProduct
role implements the interface for the ʻAbstractProduct` role. In the sample program, the following classes serve this role:
--ListLink
class, ListTray
class, ListPage
class
--TableLink
class, TableTray
class, TablePage
class
factory/listfactory/list_factory.py
from factory.factory import Factory, Link, Tray, Page
... (snip)
class ListLink(Link):
def __init__(self, caption, url):
super().__init__(caption, url)
def makeHtml(self):
return ' <li><a href="{}">{}</a></li>\n'.format(self.url, self.caption)
class ListTray(Tray):
def __init__(self, caption):
super().__init__(caption)
def makeHtml(self):
buf = []
buf.append('<li>\n')
buf.append(self.caption + '\n')
buf.append('<ul>\n')
for item in self.tray:
buf.append(item.makeHtml())
buf.append('</ul>\n')
buf.append('</li>\n')
return ''.join(buf)
class ListPage(Page):
def __init__(self, title, author):
super().__init__(title, author)
def makeHtml(self):
buf = []
buf.append('''
<html>
<head><title>{}</title></head>
'''.format(self.title))
buf.append('<body>\n')
buf.append('<h1>{}</h1>'.format(self.title))
buf.append('<ul>')
for item in self.content:
buf.append(item.makeHtml())
buf.append('</ul>')
buf.append('<hr><adress>{}</adress>'.format(self.author))
buf.append('</body>\n</html>\n')
return ''.join(buf)
factory/tablefactory/table_factory.py
from factory.factory import Factory, Link, Tray, Page
... (snip)
class TableLink(Link):
def __init__(self, caption, url):
super().__init__(caption, url)
def makeHtml(self):
return '<td><a href={}>{}</a></td>'.format(self.url, self.caption)
class TableTray(Tray):
def __init__(self, caption):
super().__init__(caption)
def makeHtml(self):
buf = []
buf.append('<td>')
buf.append('<table width="100%" border="1"><tr>')
buf.append('<td bgcolor="#cccccc" algin="center" colsapn="{}"><b>{}</b></td>'.format(len(self.tray), self.caption))
buf.append('</tr>\n')
buf.append('<tr>\n')
for item in self.tray:
buf.append(item.makeHtml())
buf.append('</tr></table>')
buf.append('</td>')
return ''.join(buf)
class TablePage(Page):
def __init__(self, title, author):
super().__init__(title, author)
def makeHtml(self):
buf = []
buf.append('''
<html>
<head><title>{}</title></head>
'''.format(self.title))
buf.append('<body>\n')
buf.append('<h1>{}</h1>'.format(self.title))
buf.append('<table width="80%" border="3">\n')
for item in self.content:
buf.append('<tr>{}</tr>'.format(item.makeHtml()))
buf.append('</table>')
buf.append('<hr><adress>{}</adress>'.format(self.author))
buf.append('</body>\n</html>\n')
return ''.join(buf)
The ConcreteFactory
role implements the interface for the ʻAbstractFactory` role. In the sample program, the following classes serve this role:
--ListFactory
class
--TableFactory
class
factory/__init__.py
from factory.listfactory.list_factory import ListFactory
from factory.tablefactory.table_factory import TableFactory
__all__ = [
"ListFactory",
"TableFactory"
]
factory/listfactory/list_factory.py
from factory.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)
... (snip)
factory/tablefactory/table_factory.py
from factory.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)
... (snip)
-[Finishing "Introduction to Design Patterns Learned in Java Language" (Not)](https://medium.com/since-i-want-to-start-blog-that-looks-like-men-do/java Introduction to Design Patterns Learned in Language-Finishing-Not-2cc9b34a30b2) -Abstract Factory pattern from "diary of tachikawa844"
Recommended Posts