Help us understand the problem. What is going on with this article?

Builderパターンに触れてみる

More than 3 years have passed since last update.

今日の目標

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

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

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away