LoginSignup
0
8

More than 3 years have passed since last update.

Pythonで、デザインパターン「Facade」を学ぶ

Last updated at Posted at 2020-01-21

GoFのデザインパターンを学習する素材として、書籍「増補改訂版Java言語で学ぶデザインパターン入門」が参考になるみたいですね。ただ、取り上げられている実例は、JAVAベースのため、自分の理解を深めるためにも、Pythonで同等のプラクティスに挑んでみました。

■ Facade(ファサード・パターン)

Facadeパターンあるいは Façadeパターン(ファサード・パターン)とは、GoF(Gang of Four; 4人のギャングたち)によって定義された、コンピュータソフトウェアのデザインパターンの1つである。Facade(ファサード)とは「建物の正面」を意味する。異なるサブシステムを単純な操作だけを持ったFacadeクラスで結び、サブシステム間の独立性を高める事を目的とする。

UML class and sequence diagram

W3sDesign_Facade_Design_Pattern_UML.jpg

UML class diagram

Example_of_Facade_design_pattern_in_UML.png
(以上、ウィキペディア(Wikipedia)より引用)

□ 備忘録

Facadeパターンは、複雑に絡み合ってごちゃごちゃした詳細をまとめ、高レベルのインタフェース(API)を提供するそうです。Facade役は、システムの外側に対してはシンプルなインタフェースを見せるそうです。また、Facade役はシステム内側にある各クラスの役割を考えて、正しい順番でクラスを利用するそうです。

そういえば、昔のOpenStack Heat(オーケストレーション)の内部構造を調査していたときに、まさに、Facadeパターンに遭遇したのを思い出しました。
確か、 OpenStack heat-engine側では、SQLAlchemy経由でデータベースを利用していて、そのデータベース用セッションを、Facadeパターンで管理していたはずです。

heat/heat/db/sqlalchemy/api.py
def get_facade():
    global _facade

    if not _facade:
        _facade = db_session.EngineFacade.from_config(CONF)
        if CONF.profiler.enabled:
            if CONF.profiler.trace_sqlalchemy:
                osprofiler.sqlalchemy.add_tracing(sqlalchemy,
                                                  _facade.get_engine(),
                                                  "db")

    return _facade

■ "Facade"のサンプルプログラム

実際に、Facadeパターンを活用したサンプルプログラムを動かしてみて、次のような動作の様子を確認したいと思います。

$ python Main.py 
welcome1.html is created for hyuki@hyuki.com (Hiroshi Yuki)
welcome2.html is created for mamoru@hyuki.com (Mamoru Takahashi)

サンプルプログラムを起動すると、2つのhtmlファイルが生成されます。
おのおのを、Webブラウザを確認してみるとこんな感じになりました。

  • welcome1.html
page1.png
  • welcome2.html
page2.png

■ サンプルプログラムの詳細

Gitリポジトリにも、同様のコードをアップしています。
https://github.com/ttsubo/study_of_design_pattern/tree/master/Facade

  • ディレクトリ構成
.
├── Main.py
├── maildata.ini
└── pagemaker
    ├── __init__.py
    ├── database.py
    ├── html_writer.py
    └── page_maker.py

(1) Facade(正面)の役

Facade役は、システムを構成しているその他大勢の役の「シンプルな窓口」となります。Facade役は、高レベルでシンプルなインタフェースをシステム外部に提供します。
サンプルプログラムでは、PageMakerクラスが、この役を努めます。

pagemaker/page_maker.py
import sys
import json
from pagemaker.database import Database
from pagemaker.html_writer import HtmlWriter

class PageMaker(object):
    @classmethod
    def makeWelcomePage(cls, mailaddr, filename):
        try:
            prop = Database.getProperties('maildata')
            username =prop[mailaddr]
            writer = HtmlWriter(open(filename, 'w'))
            writer.title('Welcom to {}s page!'.format(username))
            writer.paragraph("We'll wait for your sending")
            writer.mailto(mailaddr, username)
            writer.close()
            print('{} is created for {} ({})'.format(filename, mailaddr, username))
        except Exception:
            print("# Failure occurred")

(2) システムを構成しているその他大勢の役

その他大勢の役は、それぞれの仕事を行いますが、Facade役のことは意識しません。Facade役から呼び出されて仕事を行いますが、その他大勢の役の方からFacade役を呼び出すことはありません。
サンプルプログラムでは、Databaseクラスと、HtmlWriterクラスが、この役を努めます。

pagemaker/database.py
from configparser import ConfigParser

class Database(object):
    @classmethod
    def getProperties(cls, dbname):
        filename = dbname + ".ini"
        conf = ConfigParser()
        try:
            conf.read(filename)
            return conf["MailAddress"]
        except Exception:
            print("Warning: [{0}] is not found.".format(filename))
maildata.init
[MailAddress]
hyuki@hyuki.com = Hiroshi Yuki
hanako@hyuki.com = Hananko Sato
tomura@hyuki.com = Tomura
mamoru@hyuki.com = Mamoru Takahashi
pagemaker/html_writer.py
class HtmlWriter(object):
    def __init__(self, writer):
        self.writer = writer

    def title(self, title):
        self.writer.write("<html>\n")
        self.writer.write("<head>")
        self.writer.write("<title>{0}</title>".format(title))
        self.writer.write("</head>\n")
        self.writer.write("<body>\n")
        self.writer.write("<h1>{0}</h1>\n".format(title))

    def paragraph(self, msg):
        self.writer.write("<p>{0}</p>\n".format(msg))

    def link(self, href, caption):
        self.writer.write("<a href=\"{0}\">{1}</a>".format(href, caption))

    def mailto(self, mailaddr, username):
        self.link("mailto:{0}".format(mailaddr), username)

    def close(self):
        self.writer.write("</body>\n")
        self.writer.write("</html>\n")
        self.writer.close()

(3) Client(依頼人)の役

Facadeパターンを利用する役です。
サンプルプログラムでは、startMainメソッドが、この役を努めます。

Main.py
from pagemaker.page_maker import PageMaker

def startMain():
    PageMaker.makeWelcomePage("hyuki@hyuki.com", "welcome1.html")
    PageMaker.makeWelcomePage("mamoru@hyuki.com", "welcome2.html")

if __name__ == '__main__':
    startMain()

■ 参考URL

0
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
8