デザインパターン(Design Pattern)#Facade


設計を意識したコードが書けるようになる為に、デザインパターン修行しました。
他のDesign Patternもちょくちょく出していきます。

前置き

デザインパターンをどういう時に、何を、どう使うのかを理解することが一先ずの目標。
(Javaというか静的型付言語は初めてで、且つpython歴もそんなに長くないので、Pythonistaぽっくないところがあると思います。ご指摘ございましたらご教授ください。)

今回は、構造に関するパターンFacadeパターン。

Facadeとは

Facade(ファサード)は複雑なシステムに対するシンプルな窓口の役を果たす。つまり、大型のロジックを簡素化し、1つのシンプルな関数呼び出しにまとめることです。

概要

ここで作るサンプルプログラムは、ユーザのWebページを作成するものです。
Facadeパターンのサンプルを作るためには、本来、「複雑に入り組んだたたくさんのクラス」が必要になります。しかし、ここではサンプルプログラムを短くするために、3つのクラスだけからなる簡単なシステムを考えます。このシステムは、メールアドレスから名前を得るデータベース(database)、HTMLファイルを作成するクラス(HTMLWriter)、Facade役として高レベルのインタフェースを提供するクラス(PageMaker)で構成されています。

全体のクラス図

database.py
from configparser import ConfigParser
import logging


class Database():

    def get_properties(self, dbname):
        filename = dbname + '.ini'
        conf = ConfigParser()
        try:
            conf.read(filename)
            prob = conf['TEST1']
            return prob
        except IOError:
            logging.exception('Warning' + filename + 'is not found.')

Databaseクラスは、データベース名("maildata")を指定して、user_nameを取得します。

maildata.ini
[TEST1]
hyuki@hyuki.com=Hiroshi Yuki
hanako@hyuki.com=Hananko Sato

参照しているデータファイル。

html_writer.py
class HtmlWriter():

    def __init__(self, writer):
        self.__writer = writer

    def title(self, title):
        self.__writer.write('<!DOCTYPE html> \n')
        self.__writer.write('<html>')
        self.__writer.write('<head>')
        self.__writer.write('<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> \n')
        self.__writer.write('<title>' + title + '</title>')
        self.__writer.write('</head>')
        self.__writer.write('<body> \n')
        self.__writer.write('<h1>' + title + '<h1> \n')

    def paragraph(self, msg):
        self.__writer.write('<p>' + msg + '</p>\n')

    def link(self, href, caption):
        self.paragraph('<a href=\'' + href + '\' >' + caption + '</a>')

    def mailto(self, mailaddr, username):
        self.link('mailto:' + mailaddr, username)

    def close(self):
        self.__writer.write('</body>')
        self.__writer.write('</html>\n')
        self.__writer.close()

HtmlWriterクラスは、簡単なWebページを作成するものです。インスタンス作成時にwriterを与えておき、そのwriterに対してHTMLを出力します。

titleメソッドはタイトルを出力するもの、paragraphメソッドは段落を出力するもの、linkメソッドはリンクを出力するもの、mailtoメソッドはメールアドレスのリンクを出力するもの、closeメソッドはHTMLの出力を終えるものです。

このクラスには、titleメソッドを一番最初に呼ばなければならないという制約が隠れています。そして窓口となるPageMakerクラスは、その制約を守るように書かれています。

page_maker.py
import logging
from html_writer import HtmlWriter
from database import Database


class PageMaker():

    def make_welcome_page(self, mailaddr, filename):
        db = Database()
        try:
            prob = db.get_properties('maildata')
            user_name = prob[mailaddr]
            writer = HtmlWriter(open(filename, mode='w'))
            writer.title('Welcome to ' + user_name + 'is page!')
            writer.paragraph(user_name + 'のページへようこそ。')
            writer.paragraph('メール待っていますね。')
            writer.mailto(mailaddr, user_name)
            writer.close()
            print(filename + ' ' + 'is created for' + mailaddr + ' ' + '(' + user_name + ')')
        except IOError as e:
            logging.exception(e)

PageMakerクラスは、DatabaseクラスとHtmlWriterクラスを組み合わせて、指定したユーザのWebページを作成するためのものです。

このクラスで定義されているpublicメソッドはmake_welcome_pageだけです。このメソッドにメールアドレスと出力ファイル名を指定すると、Webページが作成されます。

HtmlWriterクラスのメソッドをごちゃごちゃ呼ぶところは、このPageMakerクラスが一手に引き受け、外部に対してはたった1つのmake_welcome_pageメソッドだけを見せています。ここがシンプルな窓口になってます。

main.py
from page_maker import PageMaker


def main():
    pm = PageMaker()
    pm.make_welcome_page('[email protected]', 'welcome.html')

if __name__ == '__main__':
    main()

実行結果
welcome.html is created [email protected] (Hiroshi Yuki)

まとめ

Facadeは、あるクラス群を使用して処理をしたい場合、そのクラス群のメソッドの呼び出しの順番や、初期化の方法が複雑な場合などの複雑さを意識しないで済むようにします。ポイントはインタフェースを少なくし、1つのシンプルな関数呼び出しにまとめることです。

その結果、外部との結合を疎にするになり、再利用し易くなります。
言い換えるなら、オブジェクト指向の情報の隠蔽を簡単に実行してくれます。

参考