Factroy_Methodパターンをさらに高度化したものが、Abstract Factoryパターンとなる。
Abstract factory
(概要)
関連する部品を組み合わせて製品を作成したい。(共通性のある部品をあらかじめ生成しておき、再利用する)
この時、抽象的な工場、抽象的なぶひんを利用して、様々な製品を作成する
(イメージ)
エンジンインターフェース
>スポーツカーのエンジン
>軽自動車のエンジン
タイヤインターフェース
>スポーツカーのタイヤ
>軽自動車のタイヤ
(目的)
・複数の部品を組み合わせることで、様々な製品を作成する。
・抽象クラスを継承したぶひんを作成することで、拡張性を高めることができる。
(仕組み)
抽象クラスを継承した複数のぶひんを組み合わせて、一つの製品を作成する。
(Factoryパターンをより複雑化したものになる)
(構成要素)
・Product : 作成するオブジェクトの部品を定義するインターフェース
・ConcreteProduct : Productを具体化したクラス(複数作成)
・Factory : Productを生成する処理を定義したインターフェース(抽象クラス)
・ConcreteFactory : ConcreteProductを作成するFactoryを具体化したクラス
Abstract Factoryパターンのサンプルコード
pythonによるサンプルコードをメモする。Abstract Factoryパターンのインターフェース(抽象クラス)をabstract_factory.pyに記述する。
これを concrete_factory.py にて読み込み、クラスを継承して具体的な処理を定義し、クラスの実行を行う。
# abstract_factory.py
from abc import ABC, abstractmethod
# 各製品の部品を生成するための、継承先となる抽象クラス(Product)
class AbcItem(ABC):
def __init__(self, caption):
self.caption = caption
@abstractmethod
def make_html(self):
pass
class PageItem(AbcItem):
def __init__(self, title, author):
self.title = title
self.author = author
self.content = []
def add(self, item):
self.content.append(item)
def write_html(self, file_name):
with open(file_name, 'w', encoding='utf-8') as fh:
fh.write(self.make_html())
class LinkItem(AbcItem):
"""<a></a>"""
def __init__(self, caption, url):
super().__init__(caption)
self.url = url
class ListItem(AbcItem):
""" <li></li> """
def __init__(self, caption):
super().__init__(caption)
self.items = []
def add(self, item):
self.items.append(item)
# Productを生成する Factory の定義
class Factory(ABC):
@abstractmethod
def create_page_item(self, title, author):
pass
@abstractmethod
def create_link_item(self, caption, url):
pass
@abstractmethod
def create_list_item(self, caption):
pass
abstract_facory.pyに定義したインターフェースを継承して、concrete_factory.pyで具体的な処理の記述および、クラス(部品)を使用して実行する。
# concrete_factory.py
from abstract_factory import(
LinkItem, ListItem, PageItem, Factory
)
class HtmlPateItem(PageItem):
def __init__(self, title, author):
super().__init__(title, author)
#abstractmethodの具体化
def make_html(self):
output = f'<html>\n<head>\n<title>{self.title}' \
f'</title>\n</head>\n'
output += f'<body>\n'
output += f'<h1>{self.title}</h1>\n'
output += f'<ul>'
for list_item in self.content:
output += list_item.make_html()
output += f'</ul>\n'
output += f'<hr>\n<address>{self.author}</address>\n'
output += '</body></html>'
return output
class HtmlLinkItem(LinkItem):
def __init__(self, caption, url):
super().__init__(caption, url)
def make_html(self):
return f'<li><a href="{self.url}">{self.caption}</a></li>'
class HtmlListItem(ListItem):
""" link item を入れる """
def __init__(self, caption):
super().__init__(caption)
def make_html(self):
output = '<li>\n'
output += self.caption + '\n'
output += '<ul>\n'
for link_item in self.items:
output += link_item.make_html()
output += '</ul>\n'
output += '</li>\n'
return output
# ConcreteProductを生成する ConcreteFactory
class HtmlFactory(Factory):
def create_page_item(self, title, author):
return HtmlPateItem(title, author)
def create_link_item(self, caption, url):
return HtmlLinkItem(caption, url)
def create_list_item(self, caption):
return HtmlListItem(caption)
if __name__ == '__main__':
html_factory = HtmlFactory()
asahi = html_factory.create_link_item('Asahi News Paper', 'http://asahi')
yomiuri = html_factory.create_link_item('Yomiuri news paper', 'http://yomiuri')
yahoo = html_factory.create_link_item('Yahoo', 'http://yahoo')
google = html_factory.create_link_item('Google', 'http://google')
wikipedia = html_factory.create_link_item('Wikipedia', 'http://wikipedia')
news_pages = html_factory.create_list_item('News Paper')
news_pages.add(asahi)
news_pages.add(yomiuri)
other_pages = html_factory.create_list_item('Other pages')
other_pages.add(yahoo)
other_pages.add(google)
other_pages.add(wikipedia)
all_page = html_factory.create_page_item('My Page', 'Taro')
all_page.add(news_pages)
all_page.add(other_pages)
all_page.write_html('tmp.html')