感謝のプログラミング 10000時間

たどり着いた結果(さき)は、感謝でした。

【プログラミング 13時間目】Facadeパターン

<スポンサーリンク>

オープンソースを読んでいたら、Facadeパターンが使われていた。
そこで気になったのでFacadeパターンを勉強してみた。

感想は、「これはやっぱり便利な考え方だ」というもの。
Facadeの考え方は当たり前のことのように見えるけれど、学習することで今後意識することができる。

Facadeの意味は「窓口」だけど、やっていることは要は「ラッピング」だ。
複雑に入り組むクラス間の関係をFacadeクラスが包み込む。
使う側からは、複雑なメソッドは意識せずに、Facadeのメソッドだけ見えていれば良い。

これはシェルを作るときなんかも皆やっていることだと思う。
子シェルを包みこむように、親シェルを作る。
そうすることによって、子のシェルの実行の順序は気にすること無く親を叩けば正しい順序でプログラムを実行してくれるようなる。

本ではこう言われている。

「はっきりと言葉で表現できるノウハウは、プログラマの頭の中に隠しておくべきものではなく、コードとして表現しておくべきものなのです」

Facadeのポイントは以下の通り
・インターフェースを少なくすること
 →外部からみて「どのAPIを使えばいいか」悩まなくていいから。
・関係しあっているクラスを適切に制御するためのクラスだと思えばいい
 →依存関係はFacadeクラスが考えておいてくれるもの。

本に載っているサンプルを写経しながら、意味を考えた。
やっぱり結城浩さんの本はわかりやすい。
ちなみに言うと、マルチスレッド編も大事に読ませていただいている。

package facade;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;

//このクラス自体はデータを持たずに、プロパティのインスタンスのみを返している。
//これはプロパティだけじゃなくて、データベースのインスタンスを返すときも使えるんじゃないか
public class Database {

	//newでインスタンスを生成させないためにprivate宣言
	//※学び1※ インスタンスを外で生成させたくないときは、privateでコンストラクタを宣言する
	private Database(){
	}
	
	public static Properties getProperties(String dbname){
		
		//※学び2※ プロパティファイルの名前は引数で指定してこのように".txt"を付け加えることで
		//プロパティファイルの名前をベタ書きせずに済む。→プロパティファイル名と「疎結合」になる
		String filename = dbname + ".txt";
		Properties prop = new Properties();
		
		try{
			prop.load(new FileInputStream(filename));
		} catch(IOException e) {
			System.out.println("Warning!: " + filename + "is not found!");
		}
		
		return prop;
	}
	
	
}
package facade;

import java.io.IOException;
import java.io.Writer;

public class HtmlWriter {
	private Writer writer;
	public HtmlWriter(Writer writer) {
		this.writer = writer;
	}
	
	public void title(String title) throws IOException {
		writer.write("<html>");
		writer.write("<head>");
		writer.write("<title>" + title + "</title>");
		writer.write("</head>");
		writer.write("<body>\n");
		writer.write("<h1>" + title + "</h1>\n");
	}
	
	public void paragraph(String msg) throws IOException {
		writer.write("<p>" + msg + "</p>\n");
	}
	
	public void link(String href, String caption) throws IOException {
		paragraph("<a href=\"" + href + "\">" + caption + "</a>");
	}
	
	public void mailto(String mailaddr, String username) throws IOException {
		link("mailto:" + mailaddr,username);
	}
	
	public void close() throws IOException {
		writer.write("</body>");
		writer.write("</html>\n");
		writer.close();
	}
}
package facade;

import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;

//facade=窓口となるクラス。
//使う側はたった1つ、makeWelcomePageメソッドだけわかればいい。
public class PageMaker {
	
	//facadeのインスタンスは作らない
	private PageMaker(){
	}
	
	//staticメソッドなので、これはPageMakerをインスタンス化しなくても使える
	//そして、使う側はメールアドレスと出力したいファイルの名前だけ渡せば、あとはfacadeがファイルを作ってくれる。
	//使う側はHtmlWriterのメソッドを意識しなくもよくなる。
	public static void makeWelcomePage(String mailaddr, String filename){
		try{
			//Database.getPropertiesもstaticメソッドである。
			//だから、インスタンス化しなくても使える。
			Properties mailprop = Database.getProperties("maildata");
			String username = mailprop.getProperty(mailaddr);
			
			HtmlWriter writer = new HtmlWriter(new FileWriter(filename));
			
			//HtmlWriterのメソッドの叩く順番をここにプログラムで表しておけば、使う人はmakeWelcomePageだけ
			//知っていればいい
			writer.title("Welcome to " + username + "'s page!");
			writer.paragraph(username + "のページへようこそ!");
			writer.paragraph("メール待ってます");
			writer.mailto(mailaddr, username);
			writer.close();
			System.out.println(filename + " is created for " + mailaddr + "(" + username + ")");
		} catch(IOException e){
			e.printStackTrace();
		}
	}
	

}
package facade;

public class Main {
	public static void main(String[] args) {
		//使う側は、「makeWelcomePageが何ができるか」だけ知っていればよく、HtmlWriterやDatabaseは
		//使う側からは見えない。
		PageMaker.makeWelcomePage("hoge@pochi.com", "Welcome.html");
	}
}