📖
Abstract Factoryパターンを学ぶ【Python】
一言で言うと
抽象的な工場/部品/製品を具体的な工場/部品/製品を作成。
・具体的な工場を複数作ることができる。
・具体的な工場に全てに新しい部品を追加しないといけないので、新しい部品を作るのは難しい.
インスタンスを作る部分はFactoryクラス。
コードサンプル
ディレクトリ構造
abstract_factory
├── factory
│ ├── factory.py
│ ├── item.py
│ ├── link.py
│ ├── page.py
│ └── tray.py
├── listfactory
│ ├── list_factory.py
│ ├── list_link.py
│ ├── list_page.py
│ └── list_tray.py
└── main.py
main.py
import sys
from factory.link import Link
from factory.page import Page
from factory.tray import Tray
from factory.factory import Factory
def main():
args = sys.argv
if len(args) != 2:
print('Usage: python moduledirectory.modulename.ConcreteFactory')
print('Example 1: python moduledirectory.modulename.ListFactory')
exit(0)
factory: Factory = Factory.get_factory(args[1])
asahi: Link = factory.create_link('朝日新聞', 'https://www.asahi.com/')
yomiuri: Link = factory.create_link('読売新聞', 'https://www.yomiuri.co.jp/')
traynews: Tray = factory.create_tray('新聞')
traynews.add(asahi)
traynews.add(yomiuri)
page: Page = factory.create_page('LinkPage', '著者')
page.add(traynews)
page.output()
if __name__ == '__main__':
main()
factory.py
from __future__ import annotations
from abc import ABCMeta, abstractmethod
from importlib import import_module
from factory.link import Link
from factory.page import Page
from factory.tray import Tray
class Factory(metaclass=ABCMeta):
@classmethod
def get_factory(cls, class_name: str) -> Factory:
module, class_ = class_name.rsplit('.', 1)
return getattr(import_module(module), class_)()
@abstractmethod
def create_link(self, caption: str, url: str) -> Link:
pass
@abstractmethod
def create_tray(self, caption: str) -> Tray:
pass
@abstractmethod
def create_page(self, title: str, author: str) -> Page:
pass
item.py
from abc import ABCMeta, abstractmethod
class Item(metaclass=ABCMeta):
def __init__(self, caption: str) -> None:
self._caption: str = caption
@abstractmethod
def make_html(self) -> str:
pass
link.py
from .item import Item
class Link(Item):
def __init__(self, caption: str, url: str) -> None:
super().__init__(caption)
self._url = url
page.py
from abc import ABCMeta, abstractmethod
from .item import Item
class Page(metaclass=ABCMeta):
_content: list = []
def __init__(self, title: str, author: str) -> None:
self.title: str = title
self.author: str = author
def add(self, item: Item) -> None:
self._content.append(item)
def output(self) -> None:
filename: str = f'{self.title}.html'
with open(filename, mode='w') as f:
f.write(self.make_html())
print(f'{filename}を作成しました。')
@abstractmethod
def make_html(self) -> str:
pass
tray.py
from .item import Item
class Tray(Item):
_tray: list = []
def __init__(self, caption: str) -> None:
super().__init__(caption)
def add(self, item: Item) -> None:
self._tray.append(item)
list_factory.py
from listfactory.list_page import ListPage
from listfactory.list_tray import ListTray
from factory.factory import Factory
from factory.link import Link
from factory.page import Page
from factory.tray import Tray
from listfactory.list_link import ListLink
class ListFactory(Factory):
def create_link(self, caption: str, url: str) -> Link:
return ListLink(caption, url)
def create_tray(self, caption: str) -> Tray:
return ListTray(caption)
def create_page(self, title: str, author: str) -> Page:
return ListPage(title, author)
list_link.py
from factory.link import Link
class ListLink(Link):
def __init__(self, caption: str, url: str) -> None:
super().__init__(caption, url)
def make_html(self) -> str:
return f' <li><a href="{self._url}">{self._caption}</a></li>'
list_page.py
from factory.page import Page
class ListPage(Page):
def __init__(self, title: str, author: str) -> None:
super().__init__(title, author)
def make_html(self) -> str:
str_buf: list = []
str_buf.append('<html><head><title></title></head>')
str_buf.append('<body>')
str_buf.append(f'<h1>{self.title}</h1>')
str_buf.append('<ul>')
for item in self._content:
str_buf.append(item.make_html())
str_buf.append('</ul>')
str_buf.append(f'<hr><adress>{self.author}</adress>')
str_buf.append('</body></html>')
return '\n'.join(str_buf)
list_tray.py
from factory.tray import Tray
class ListTray(Tray):
def __init__(self, caption: str) -> None:
super().__init__(caption)
def make_html(self) -> str:
str_buf: list = []
str_buf.append('<li>')
str_buf.append(self._caption)
str_buf.append('<ul>')
for item in self._tray:
str_buf.append(item.make_html())
str_buf.append('</ul>')
str_buf.append('</li>')
return '\n'.join(str_buf)
Discussion