【Java】Builderパターン【デザインパターン】
目次
Builderパターンについて
Builderパターンとは
- 全体を構成している、各部分部分の処理を積上げていくためのパターンです
サンプルプログラム
- Builderパターンを使って、タイトル、文字列、箇条項目を含む文章を作成する例を取り上げます
- 各クラスの役割は以下のようになっています
名前 | 役割 |
---|---|
Builder | 文章を構成するメソッドを定めた抽象クラス 表現形式を決定する |
Director | 一つの文章を作るクラス 作成過程を決定する |
TextBuilder | プレーンテキストで文章を作るクラス |
HTMLBuilder | HTMLファイルでで文章を作るクラス |
Builderクラス
- 文章を作るメソッドを宣言する抽象クラスです
public abstract class Builder { public abstract void makeTitle(String title); public abstract void makeString(String str); public abstract void makeItems(String[] items); public abstract void close(); }
Directorクラス
- Builderクラスで宣言されているメソッドで文章を作ります
- Builderクラスは抽象クラスなので、インスタンスを生成できません
- Directorクラスのコンストラクタに渡されるのは、Builderクラスのサブクラスのインスタンスです
- 与えられたインスタンスの種類によって、Direntorで作るインスタンスの形式が決まります
public class Director { private Builder builder; public Director(Builder builder) { // 与えられたBuilderのサブクラスのインスタンスを、builderフィールドに保持 this.builder = builder; } public void construct() { // 文書構築メソッド builder.makeTitle("Greeting"); // タイトル builder.makeString("朝から昼にかけて"); // 文字列 builder.makeItems(new String[]{ // 箇条書き "おはようございます。", "こんにちは。", }); builder.makeString("夜に"); // 別の文字列 builder.makeItems(new String[]{ // 別の箇条書き "こんばんは。", "おやすみなさい。", "さようなら。", }); builder.close(); // 文書を完成させる } }
TextBuilderクラス
- Builderクラスのサブクラスです
public class TextBuilder extends Builder { private StringBuffer buffer = new StringBuffer(); public void makeTitle(String title) { buffer.append("==============================\n"); buffer.append("『" + title + "』\n"); buffer.append("\n"); } public void makeString(String str) { buffer.append('■' + str + "\n"); buffer.append("\n"); } public void makeItems(String[] items) { for (int i = 0; i < items.length; i++) { buffer.append(" ・" + items[i] + "\n"); } buffer.append("\n"); } public void close() { buffer.append("==============================\n"); } public String getResult() { // 完成した文書 return buffer.toString(); // StringBufferをStringに変換 } }
HTMLBuilderクラス
- Builderクラスのサブクラスです
- 文章を構築し、HTMLファイル名を返します
import java.io.*; public class HTMLBuilder extends Builder { private String filename; // 作成するファイル名 private PrintWriter writer; // ファイルに書き込むPrintWriter public void makeTitle(String title) { filename = title + ".html"; try { writer = new PrintWriter(new FileWriter(filename)); } catch (IOException e) { e.printStackTrace(); } writer.println("<html><head><title>" + title + "</title></head><body>"); writer.println("<h1>" + title + "</h1>"); } public void makeString(String str) { writer.println("<p>" + str + "</p>"); } public void makeItems(String[] items) { writer.println("<ul>"); for (int i = 0; i < items.length; i++) { writer.println("<li>" + items[i] + "</li>"); } writer.println("</ul>"); } public void close() { writer.println("</body></html>"); writer.close(); } public String getResult() { // 完成した文書のファイル名を返す return filename; } }
Mainクラスで動作確認
public class Main { public static void main(String[] args) { if (args.length != 1) { usage(); System.exit(0); } if (args[0].equals("plain")) { TextBuilder textbuilder = new TextBuilder(); Director director = new Director(textbuilder); director.construct(); String result = textbuilder.getResult(); System.out.println(result); } else if (args[0].equals("html")) { HTMLBuilder htmlbuilder = new HTMLBuilder(); Director director = new Director(htmlbuilder); director.construct(); String filename = htmlbuilder.getResult(); System.out.println(filename + "が作成されました。"); } else { usage(); System.exit(0); } } public static void usage() { System.out.println("Usage: java Main plain プレーンテキストで文書作成"); System.out.println("Usage: java Main html HTMLファイルで文書作成"); } }
Builderパターンのメリット
- MainはDirectorクラスのconstructメソッドのみを呼び出し、
- DirectorクラスはConcreteBuilderクラスに依存せず、Builderクラスのメソッドのみを利用します
- →ConcreteBuilderクラスは必要に応じて変更することができます
- Builderの抽象メソッドにどのような動作が期待されているのかを知っておくのが重要です
今日のポイント
- 全体を構成している、各部分部分の処理を積上げていくためのパターンです
- DirectorクラスはConcreteBuilderクラスに依存しないので、必要に応じて変更することができます
- 例えば、同じ文書を要求に合わせて、異なる表現形式で出力することができます
本日もお疲れ様です😊