はじめに
本エントリーは某社内で実施するデザインパターン勉強会向けの資料となります。
本エントリーで書籍「Java言語で学ぶデザインパターン入門」をベースに学習を進めますが、サンプルコードはC#に置き換えて解説します。
第1回:Iteratorパターン
第2回:Adapterパターン
第3回:Template Methodパターン
第4回:Factory Methodパターン
第5回:Singletonパターン
第6回:Prototypeパターン
第7回:Builderパターン
第8回:Abstract Factoryパターン
第9回:Bridgeパターン
第10回:Strategyパターン
第11回:Compositeパターン
第12回:Decoratorパターン
第13回:Visitorパターン
第14回:Chain of Responsivilityパターン
Facadeパターンとは
複雑な内部処理をまとめ、システムの外側にシンプルなAPI(Application Programming Interface:ソフトウェアの機能や管理するデータなどを、外部の他のプログラムから呼び出して利用するための手順やデータ形式を定めた規約)を提供するデザインパターンを指す。
役割名 | 役割 |
---|---|
Facade | システムを構成するその他のクラスの機能をまとめたAPIをシステム外部に提供する |
その他のクラス | 各クラスで定義された機能を実装する |
Client | Facadeを利用する |
※Facadeクラス自体をその他のクラスとみなし、再帰的にFacadeパターンを適用することも可能である。 |
サンプルプログラムのクラス図
各クラスの役割
以下に各クラスの役割を示す。
クラス名 | 役割 | 概要 |
---|---|---|
Database | その他のクラス | ユーザー名を利用し、リソースファイルに登録されているメールアドレスの検索を行う |
HtmlWriter | その他のクラス | 指定された情報を利用し、HTMLタグを生成する |
PageMaker | Facade | DatabaseとHtmlWriterを利用したHTMLページ作成処理を実行する |
Program | Client | 動作確認用の実行クラス |
Databaseクラス
ユーザー名を利用し、リソースファイルに登録されているメールアドレスの検索を行う。
using System;
using System.Collections.Generic;
namespace FacadePatternConsole.PageMaker
{
/// <summary>
/// ユーザー名を利用し、リソースファイルに登録されているメールアドレスの検索を行う
/// </summary>
class Database
{
private Database() { }
/// <summary>
/// ユーザ名からメールアドレスを検索する
/// </summary>
/// <param name="userName"></param>
/// <returns></returns>
public static string GetUserMailAddr(string userName)
{
return MailData.ResourceManager.GetString(userName);
}
}
}
HtmlWriterクラス
指定された情報を利用し、HTMLタグを生成する。
各メソッドの機能は以下の通り。
メソッド名 | 役割 |
---|---|
WriteTitle | HTMLページのタイトル部分を構成するタグ(html, head, title, body, h1)を生成する |
WriteParagraph | HTMLページの段落を構成するタグ(p)を生成する |
WriteLink | HTMLページのリンクを構成するタグ(a href)を生成する |
WriteMailTo | メールアドレス部分の文字列を生成する |
Close | body, headの末尾を生成する |
using System;
using System.IO;
namespace FacadePatternConsole.PageMaker
{
/// <summary>
/// 指定された情報を利用し、HTMLタグを生成する
/// </summary>
class HtmlWriter:IDisposable
{
public StreamWriter _writer { get; set; }
public HtmlWriter(StreamWriter writer)
{
this._writer = writer;
}
/// <summary>
/// HTMLページのタイトル部分を構成するタグ(html, head, title, body, h1)を生成する
/// </summary>
/// <param name="title">HTMLページのタイトル</param>
public void WriteTitle(string title)
{
_writer.Write("<html>");
_writer.Write("<head>");
_writer.Write("<title>" + title + "</title>");
_writer.Write("</head>");
_writer.Write("<body>\n");
_writer.Write("<h1>" + title + "<h1>");
}
/// <summary>
/// HTMLページの段落を構成するタグ(p)を生成する
/// </summary>
/// <param name="msg"></param>
public void WriteParagraph (string msg)
{
_writer.Write("<p>" + msg + "</p>\n");
}
/// <summary>
/// HTMLページのリンクを構成するタグ(a href)を生成する
/// </summary>
/// <param name="href"></param>
/// <param name="caption"></param>
public void WriteLink(string href, string caption)
{
_writer.Write("<a href=\"" + href+ "\">" + caption + "</p>\n");
}
/// <summary>
/// メールアドレス部分の文字列を生成する
/// </summary>
/// <param name="mailAddr"></param>
/// <param name="userName"></param>
public void WriteMailTo(string mailAddr, string userName)
{
WriteLink(("mailto:" + mailAddr), userName);
}
/// <summary>
/// body, headの末尾を生成する
/// </summary>
public void Close()
{
_writer.Write("</body>");
_writer.Write("</html>\n");
}
public void Dispose()
{
_writer.Dispose();
}
}
}
PageMakerクラス
DatabaseクラスとHtmlWriterクラスを利用し、指定したユーザのWebページのHTMLを生成する。
HTMLページの生成に必要な操作(リソースからの情報取得、HTMLタグの生成・構成)は全てPageMaker.MakeWelcomePageメソッド内で完結している。
このため、Clientは適切な引数を指定してPageMaker.MakeWelcomePageメソッドを呼び出すのみでよい。
using System;
using System.IO;
using System.Text;
namespace FacadePatternConsole.PageMaker
{
/// <summary>
/// DatabaseとHtmlWriterを利用したHTMLページ作成処理を実行する
/// </summary>
class PageMaker
{
private PageMaker() { }
/// <summary>
/// 指定したユーザとファイル名でHTMLページを作成する
/// </summary>
/// <param name="userName"></param>
/// <param name="fileName"></param>
public static void MakeWelcomePage(string userName, string fileName)
{
// メールアドレスの検索
string mailAddr = Database.GetUserMailAddr(userName);
// htmlの作成
using (HtmlWriter writer = new HtmlWriter(new StreamWriter(fileName,false,Encoding.Unicode)))
{
writer.WriteTitle("Welcome to" + userName + "'s Page!");
writer.WriteParagraph(userName + "のページへようこそ");
writer.WriteParagraph("メールまってますね。");
writer.WriteMailTo(mailAddr, userName);
writer.Close();
}
// HTML出力先の表示
Console.WriteLine(fileName + @" is created for " + mailAddr + @" (" + userName + @")");
Console.ReadKey();
}
}
}
Programクラス
PageMakerクラスのMakeWelcomePageメソッドを呼び出し、 HTMLファイルの生成を指示する。
HTMLファイル生成の手順はMakeWelcomePageメソッド内でカプセル化されており、Programクラス側ではMakeWelcomePageメソッドの呼び出しのみを行えばよい。
using System;
namespace FacadePatternConsole
{
class Program
{
/// <summary>
/// 動作確認用の実行クラス
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
PageMaker.PageMaker.MakeWelcomePage("Piyo_Taroh", "welcome.html");
}
}
}
実行結果
Facadeパターン使用によるメリット
Facadeパターンは、複数のクラス・メソッドからなる複雑な処理をまとめて1つのAPIを提供する。この特徴より、以下の利点が得られると考えられる。
- クラス・メソッドの集合(パッケージ)の外部との結合度を下げ、再利用性を高める
- 複数の処理の集合に対し一律の窓口を提供することで、利用者側での実装負担を軽減する
パッケージ・フレームワークの規模が大きくなればなるほどクラスやメソッドは増加し、利用したい機能についてどの操作を行えばよいかが不明瞭になりがちである。このような場合にFacadeパターンを適用し、提供したい機能と呼び出すメソッドが一対一対応するように設計するとよいだろう。
サンプルコード
以下に公開しています。
https://github.com/aconit96/FacadePatternConsole