Python デザインパターン サンプルコード Template Method
結城 浩「Java言語で学ぶデザインパターン入門」をPython化
Python3(3.11)で動くソースコード(.pyファイル .ipynbファイル)あります
「anaconda3」on .py「PyCharm」.ipynb「Jupyter Notebook」
(2023-11-18)Python3.11で動作確認済み
正常に動作して出力も正常なのだが,エラーではない警告が出る。Python3.12ではあるモジュールが使えなくなるらしい。
Database (getProperties) HtmlWriter (title, pragraph, link, mailto, close) PageMaker (makeWelcomePage)class Database は,ユーザリストからEメールアドレスとユーザ名を読み込みます。
◆◆html コードの知識◆◆
html コードの知識は Facade パターンとはまったく関係ないのですがいちおう知っておいた方がよいと考えます。
html コードとブラウザでの見た目との関係をおよそ知ってもらえれば十分です。
サンプルが出力したhtml コードを巻末に掲載してあります。同時にそれをブラウザで見ているはずです。それを見ただけで html コードとブラウザでの見た目との関係の概略は判るでしょう。
html コードは「<>」の中に書きます。それをタグと言います。タグの外に書いたものはブラウザで見ることができます。タグは対になっているものが多いですからタグとタグの間に書いたものがブラウザで見ることができます。実際にそうなっていることを確認できるでしょう。見て判ると思いますが,部品化し易いコード体系になっています。
Web ページであることを示すために対タグ「html」「head」「body」をサンプルのように並べます。対タグ「head」の間には,html文書,タイトル,文字コードなどを宣言します。対タグ「body」の間には,ブラウザで見ることができる本文とそれを修飾するタグを書きます。
本文を修飾するタグについては詳細を省略します。サンプルで雰囲気だけつかんでください。なお,タグ「a」はリンクであり,ここにユーザリストの内容が使われています。
◆◆Facade パターンの実装◆◆
最初に注意しておきたいのは,48行目,62行目のメソッドの呼び出し時にインスタンス化してありません。Java サンプルでは private にしてインスタンス化を拒否しています。たしかにこのパターンはめずらしく抽象クラス(Java では interface)がないし,クラスの親子関係もないし,ましてやオーバーライドもないです。Python サンプルでは判りませんが,Java サンプルでは,インスタンスの型(所属クラス)と new する(インスタンス化する)クラスが違うことが普通です。クラスの親子関係とコンストラクタがなければインスタンス化しなくても支障がないのか!?
class Database では,クライアント;メインルーチンから与えられる Eメールアドレスよりユーザ名を検索するため設定ファイルを使っています。Python で設定ファイルを読み込むには ConfigParser または SafeConfigParser を使います。詳細な使い方はサンプルコードのとおりです。このサンプルでは設定ファイルを使っていますが,dict 辞書でも同じ効果が得られます。
class HtmlWriter では,html コードの部品を集めてあります。上でも書きましたが html コードは部品化しやすい構造になっています。このサンプルでは,くしくも使う順に並んでいますが,デタラメの順でかまいません。
使い方の典型例を示すのは class HtmlWriter クラスではなく,Facade オブジェクトである class PageMaker なのです。html コードの部品がなぜこの順に並んでいるのかはファイルの出力(巻末に掲示)を見れば判ります。Webページの作り方の詳細はここでは省略します。
Facade オブジェクトのおかげでクライアント;メインルーチンは Eメールアドレスとタイトルだけ指定するだけです。つくりたいWebページの様式に合わせてFacade オブジェクトである class PageMaker は作り替えが必要になるでしょう。
◆◆ソースコード◆◆
このWebページの左上隅からダウンロードできます。
1つのソースファイル,1つの設定ファイル,1つのサンプル出力があります。
・Facade.py;Facade パターンのPythonサンプル
・maildata.txt;設定ファイル形式のユーザリスト(Facade.pyと同じディレクトリ)
・welcome.html;サンプルプログラムの出力ファイル(Facade.pyと同じディレクトリ)
【Facade.py】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
#!/usr/bin/env python3 # -*- coding: utf-8 -*- import sys from configparser import SafeConfigParser from logging import getLogger logger = getLogger(__name__) class Database(): def getProperties(self, dbname): filename = dbname + ".txt" config = SafeConfigParser() try: config.read(filename) prop = config["Properties"] return prop except IOError: logger.exception("Warning {} is not found.".format(filename)) class HtmlWriter(): def __init__(self, writer): self.writer = writer def title(self, title): self.writer.write("<!DOCTYPE html> \n") self.writer.write("<html>\n") self.writer.write("<head>\n") self.writer.write( '<meta http-equiv="Content-Type" content="text/html; \ charset=shift_jis">\n') self.writer.write("<title>{}</title>\n".format(title)) self.writer.write("</head>\n") self.writer.write("<body>\n") self.writer.write("<h1>{}</h1>\n".format(title)) def paragraph(self, msg): self.writer.write("<p>{}</p>\n".format(msg)) def link(self, href, caption): self.paragraph('<a href="{}">{}</a>'.format(href, caption)) def mailto(self, mailaddr, username): self.link("mailto:" + mailaddr, username) def close(self): self.writer.write("</body>\n") self.writer.write("</html>\n") self.writer.close() class PageMaker(): def makeWelcomePage(self, mailaddr, filename): try: mailprop = Database().getProperties("maildata") username = mailprop[mailaddr] writer = HtmlWriter(open(filename, mode="w")) writer.title("Welcome to {}'s page!".format(username)) writer.paragraph("{}のページへようこそ。".format(username)) writer.paragraph("メールまっていますね。") writer.mailto(mailaddr, username) writer.close() print("{} is created {} ({})". format(filename, mailaddr, username)) except IOError as e: logger.exception(e) def main(): PageMaker().makeWelcomePage("hyuki@hyuki.com", "welcome.html") if __name__ == '__main__': main() #### #【maildata.txt】 [Properties] hyuki@hyuki.com=Hiroshi Yuki hanako@hyuki.com=Hanako Sato tomura@hyuki.com=Tomura mamoru@hyuki.com=Mamoru Takahashi
1 2 3 4 5 6 7 8 9 10 11 12 13
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=shift_jis"> <title>Welcome to Hiroshi Yuki's page!</title> </head> <body> <h1>Welcome to Hiroshi Yuki's page!</h1> <p>Hiroshi Yukiのページへようこそ。</p> <p>メールまっていますね。</p> <p><a href="mailto:hyuki@hyuki.com">Hiroshi Yuki</a></p> </body> </html>
Hiroshi Yukiのページへようこそ。
メールまっていますね。