En tant que matériel d'apprentissage des modèles de conception du GoF, le livre «Introduction aux modèles de conception appris dans le langage Java augmenté et révisé» semble être utile. Cependant, comme les exemples repris sont basés sur JAVA, j'ai essayé la même pratique avec Python pour approfondir ma compréhension.
Le modèle Abstract Factory est l'un des modèles de conception définis par GoF (Gang of Four; 4 gangs). Le but est de rationaliser la réutilisation de plusieurs modules en agrégeant les API pour générer des instances associées. En japonais, il est souvent traduit par «usine abstraite». Aussi appelé modèle de kit
UML class and sequence diagram UML class diagram (Ce qui précède est cité sur Wikipedia)
Le modèle Abstract Factory semble créer un produit abstrait en combinant des parties abstraites de ** abstract factory **. En fait, j'aimerais exécuter le code d'implémentation Python de Abstract Factory pour avoir une idée de la ** abstract factory **. L'exemple de programme repris ici crée une collection de liens avec une structure hiérarchique sous forme de fichier HTML.
ListFactory
, un fichier HTML de liens au format liste sera généré.TableFactory
, un fichier HTML d'une collection de liens tabulaires est généré.Tout d'abord, exécutons le code qui crée la page Web ** basée sur un lien **.
$ python Main.py ListFactory
[LinkPage.html] was created.
Un fichier appelé «LinkPage.html» a été généré. Lorsque j'ai vérifié l'apparence avec un navigateur Web, cela ressemblait à ceci.
Ensuite, exécutons le code qui crée une page Web ** basée sur une table **.
$ python Main.py TableFactory
[LinkPage.html] was created.
Un fichier appelé «LinkPage.html» a été généré. Lorsque j'ai vérifié l'apparence avec un navigateur Web, cela ressemblait à ceci.
Un code similaire a été téléchargé dans le référentiel Git. https://github.com/ttsubo/study_of_design_pattern/tree/master/AbstractFactory
.
├── Main.py
└── factory
├── __init__.py
├── factory.py
├── listfactory
│ ├── __init__.py
│ └── list_factory.py
└── tablefactory
├── __init__.py
└── table_factory.py
Le rôle ʻAbstractProduct définit l'interface des parties abstraites et des produits créés par le rôle ʻAbstractFactory
. Dans l'exemple de programme, les classes Link
, Tray
et Page
remplissent ce rôle.
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
Le rôle ʻAbstractFactory définit l'interface pour créer une instance du rôle ʻAbstractProduct
.
Dans l'exemple de programme, la classe Factory
remplit ce rôle.
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)
Le rôle Client
fait son travail en utilisant uniquement les interfaces des rôles ʻAbstractFactory et ʻAbstractProduct
.
Le rôle du «Client» ne connaît pas les pièces, produits ou usines spécifiques. Dans l'exemple de programme, la méthode startMain
remplit ce rôle.
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())
Le rôle ConcreteProduct
implémente l'interface pour le rôle ʻAbstractProduct`. Dans l'exemple de programme, les classes suivantes remplissent ce rôle:
ListLink
, classe ListTray
, classe ListPage
TableLink
, classe TableTray
, classe TablePage
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)
Le rôle ConcreteFactory
implémente l'interface pour le rôle ʻAbstractFactory`. Dans l'exemple de programme, les classes suivantes remplissent ce rôle:
ListFactory
TableFactory
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)
Recommended Posts