今日の目標
JavaのBuilderパターンとはどういったものなのかを知る
使うもの
ではスタート
はじめに
まずはBuilderパターンとはどのようなものなのかをWikipediaさんで調べてみる。
Builder パターン(ビルダー・パターン)とは、GoF(Gang of Four; 4人のギャングたち)によって定義されたデザインパターンの1つである。 オブジェクトの生成過程を抽象化することによって、動的なオブジェクトの生成を可能にする。(wikipedia-Builderパターン)
いつもよりも意味がわからなくて困る。
本のサンプルを参考にしてみる
本のサンプルがとてもわかりやすかったです。
登場人物は以下の3クラス。
- Builder
- インスタンスの部品を作るためのメソッドが用意された抽象クラス
- Director
- Builderで用意されているメソッドを使ってインスタンスを生成するクラス
- ConcreteBuilder
- Builderを継承してメソッドの実装をするクラス
サンプルでは文書を作成するプログラムを組んでいました。テキストファイルとHTMLファイルを生成するプログラムでしたが、ここでは少し変えてHTMLファイルとMDファイルを作るプログラムにしてます。もう少し工夫したら実用的なプログラムになりそうだなあ、という印象。
登場人物Builder。
package builder;
public abstract class Builder {
// 文書のタイトルを作る
public abstract void makeTitle(String title);
// 見出しを作る
public abstract void makeHeading(String heading);
// 文書の本文を作る
public abstract void makeContents(String contents);
// 文書作成を完了する
public abstract void close();
}
登場人物Director。こいつはBuilderしか見てません。でも見ているBuilderは実装を持ってないので、実際はConcreteBuilderを相手にしてます。
import builder.Builder;
public class Director {
private Builder builder;
// 実際はBuilderのサブクラスを引数に取る
public Director(Builder builder) {
this.builder = builder;
}
// 文章の中身を作る
public void construct() {
builder.makeTitle("Builderパターンのお勉強");
builder.makeHeading("今日の目標");
builder.makeContents("Builderパターンがどういうものなのかを知る");
builder.makeHeading("使うもの");
builder.makeContents("Java言語で学ぶデザインパターン入門");
builder.close();
}
}
登場人物ConcreteBuilderの1つ。Builderを継承して、実装を担当してます。Directorから渡された引数にhtmlタグを付け足してファイル出力してます。
package concreteBuilder;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import builder.Builder;
public class HtmlBuilder extends Builder {
private String filename;
private StringBuffer sb = new StringBuffer();
public HtmlBuilder(String filename) {
this.filename = filename + ".html";
}
@Override
public void makeTitle(String title) {
sb.append("<html><head><title>" + title + "</title></head>");
sb.append("<body>");
sb.append("<h1>" + title + "</h1>");
}
@Override
public void makeHeading(String heading) {
sb.append("<h3>" + heading + "</h3>");
}
@Override
public void makeContents(String contents) {
sb.append("<p>" + contents + "</p>");
}
@Override
public void close() {
sb.append("</body></html>");
try (PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File(filename)), "UTF-8")))) {
pw.println(sb.toString());
} catch(Exception e) {
e.printStackTrace();
}
}
public String getResult() {
return filename;
}
}
登場人物ConcreteBuilderの1つ。こちらはDirectorから渡された引数にMarkdownの部品を付け足してファイル出力してます。
package concreteBuilder;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import builder.Builder;
public class MdBuilder extends Builder {
private String filename;
private StringBuffer sb = new StringBuffer();
public MdBuilder(String filename) {
this.filename = filename + ".md";
}
@Override
public void makeTitle(String title) {
sb.append("# " + title + "\n");
}
@Override
public void makeHeading(String heading) {
sb.append("## " + heading + "\n");
}
@Override
public void makeContents(String contents) {
sb.append(contents + "\n");
}
@Override
public void close() {
try (PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File(filename)), "UTF-8")))) {
pw.println(sb.toString());
} catch(Exception e) {
e.printStackTrace();
}
}
public String getResult() {
return filename;
}
}
最後はMainクラス。ConcreteBuilderのインスタンスをDirectorクラスに渡してconstructメソッドを実行してます。
import concreteBuilder.HtmlBuilder;
import concreteBuilder.MdBuilder;
public class Main {
public static void main(String[] args) {
if(args.length != 1) {
usage();
System.exit(0);
}
if(args[0].equals("html")) {
HtmlBuilder hb = new HtmlBuilder("qiita1");
Director director = new Director(hb);
director.construct();
System.out.println(hb.getResult() + "を作成しました。");
} else if(args[0].equals("md")) {
MdBuilder mb = new MdBuilder("qiita1");
Director director = new Director(mb);
director.construct();
System.out.println(mb.getResult() + "を作成しました。");
} else {
usage();
System.exit(0);
}
}
private static void usage() {
System.out.println("Usage: java Main html HTMLファイルで文書作成");
System.out.println("Usage: java Main md MDファイルで文書作成");
}
}
結果はこちら。
なかなか面白いパターンでした。