[GO] Apprenez le modèle de conception "Abstract Factory" avec Python

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.

■ Usine abstraite

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 W3sDesign_Abstract_Factory_Design_Pattern_UML.jpg UML class diagram 68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3130333539352f62393731323034392d616664392d323330332d653539372d3031393136333530633732382e706e67.png (Ce qui précède est cité sur Wikipedia)

■ Exemple de programme "Abstract Factory"

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.

(1) Essayez d'exécuter ListFactory

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. listfactory.png

(2) Essayez d'exécuter TableFactory

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. tablefactory.png

■ Détails de l'exemple de programme

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

(1) Le rôle de AbstractProduct

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

(2) Le rôle de AbstractFactory

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)

(3) Le rôle du client

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())

(4) Le rôle du produit en béton

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:

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)

(5) Le rôle de l'usine de béton

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:

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)

■ URL de référence

Recommended Posts

Apprenez le modèle de conception "Abstract Factory" avec Python
Apprenez le modèle de conception "Méthode d'usine" en Python
Apprenez le modèle de conception "Prototype" avec Python
Apprenez le modèle de conception "Builder" avec Python
Apprenez le modèle de conception "Flyweight" en Python
Apprenez le modèle de conception "Observer" en Python
Apprenez le modèle de conception "Memento" avec Python
Apprenez le modèle de conception "Proxy" en Python
Apprenez le modèle de conception "Commande" en Python
Apprenez le modèle de conception "Visiteur" avec Python
Apprenez le modèle de conception "Bridge" avec Python
Apprenez le modèle de conception "Mediator" avec Python
Apprenez le modèle de conception "Décorateur" avec Python
Apprenez le modèle de conception "Iterator" avec Python
Apprenez le modèle de conception «Stratégie» avec Python
Apprenez le modèle de conception "Composite" avec Python
Apprenez le modèle de conception "État" en Python
Apprenez le modèle de conception "Adapter" avec Python
Apprenez le modèle de conception "Méthode de modèle" en Python
Apprenez le modèle de conception «Chaîne de responsabilité» en Python
Apprenez le modèle de conception "Singleton" avec Python
Apprenez le modèle de conception "Façade" avec Python
Implémenter le modèle Singleton en Python
Motif singleton en Python
[Gang of Four] Apprentissage des modèles de conception - Usine abstraite
Design Pattern #Factory, méthode
Modèle de visiteur en Python
J'ai écrit un modèle de conception dans l'édition Kotlin Factory
Trouver des erreurs en Python
Modèles de conception en Python: introduction
Python Design Pattern - Méthode de modèle
Obtenir l'API arXiv en Python
Python dans le navigateur: la recommandation de Brython
Enregistrez le fichier binaire en Python
Frappez l'API Sesami en Python
Obtenez le chemin du bureau en Python
Obtenez le chemin du script en Python
Dans la commande python, python pointe vers python3.8
Accédez à l'API Web en Python
J'ai écrit la file d'attente en Python
Calculer le mois précédent en Python
Examiner la classe d'un objet avec python
Obtenez le chemin du bureau en Python
Obtenez le nom d'hôte en Python
Accéder à l'API Twitter avec Python
La première étape de Python Matplotlib
J'ai écrit la pile en Python
Maîtriser le module lowref en Python
Apprenez les bases de Python ① Débutants élémentaires
Charger le SDK Python distant avec IntelliJ
Essayez d'utiliser l'API Wunderlist en Python
Vérifiez le comportement du destroyer en Python
[Python Kivy] À propos de la modification du thème de conception
Essayez d'utiliser l'API Kraken avec Python
Apprenez les bases en touchant les variables python
Ecrire le test dans la docstring python
Prenez la somme logique de List en Python (fonction zip)
Modèle de conception du GoF à partir du problème 2. Structure