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