LoginSignup
8

More than 5 years have passed since last update.

posted at

Builderパターンに触れてみる

今日の目標

JavaのBuilderパターンとはどういったものなのかを知る

使うもの

ではスタート

はじめに

まずはBuilderパターンとはどのようなものなのかをWikipediaさんで調べてみる。

Builder パターン(ビルダー・パターン)とは、GoF(Gang of Four; 4人のギャングたち)によって定義されたデザインパターンの1つである。 オブジェクトの生成過程を抽象化することによって、動的なオブジェクトの生成を可能にする。(wikipedia-Builderパターン

いつもよりも意味がわからなくて困る。

本のサンプルを参考にしてみる

本のサンプルがとてもわかりやすかったです。

登場人物は以下の3クラス。

  • Builder
    • インスタンスの部品を作るためのメソッドが用意された抽象クラス
  • Director
    • Builderで用意されているメソッドを使ってインスタンスを生成するクラス
  • ConcreteBuilder
    • Builderを継承してメソッドの実装をするクラス

サンプルでは文書を作成するプログラムを組んでいました。テキストファイルとHTMLファイルを生成するプログラムでしたが、ここでは少し変えてHTMLファイルとMDファイルを作るプログラムにしてます。もう少し工夫したら実用的なプログラムになりそうだなあ、という印象。

登場人物Builder。

Builder.java
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を相手にしてます。

Director.java


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タグを付け足してファイル出力してます。

HtmlBuilder.java
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の部品を付け足してファイル出力してます。

MdBuilder.java
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メソッドを実行してます。

Main.java
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ファイルで文書作成");
    }

}

結果はこちら。

java Main html
builderPattern1.png

builderPattern2.png

java Main md
builderPattern3.png

なかなか面白いパターンでした。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
8