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

Builderパターン(Effective Java)

More than 1 year has passed since last update.

最近になって、主にJavaでEffective JavaのBuilderパターンを利用する機会が多かったため自分の整理用に書き留めておきます。あくまで簡単なまとめです。

Builderパターン例

例えば、Android開発しているときにOKHttpClientを使いたいとすると、

OkHttpClient okHttpClient = new OkHttpClient(); 

と、インスタンスを生成しますが、ここでレスポンスをログに出力したいなと思ったら

 OkHttpClient okHttpClient = new OkHttpClient.Builder()
                        .addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))
                          .build();

としたりします。これがBuilderパターンの例です。

何をしているのか

通常であれば、クラスは使う側がnewすることでインスタンスを生成しますが、Builderパターンの場合はちょっと違います。

クラスの中にstaticなクラスを用意してあげます。

public class Example {
    private int a;
    private int b;
    private int c;
    private int d;
    private int e;

    public static class ExampleBuilder {
        private int a;
        private int b;
        private int c;
        private int d;
        private int e;

    }
}

そして、フィールドに値をセットし、Builderそれ自身を返すメソッドをフィールドごとに生やします。

public class Example {
    private int a;
    private int b;
    private int c;
    private int d;
    private int e;

    public static class ExampleBuilder {
        private int a;
        private int b;
        private int c;
        private int d;
        private int e;

        public Builder a(int a) {
            this.a = a;
            return this;
        }

        public Builder b(int b) {
            this.b = b;
            return this;
        }
        //c, dは省略
        public Builder e(int e) {
            this.e = e;
            return this;
        }

    }
}

一方そのころ、Exampleクラスにはprivateなコンストラクタを用意します。

public class Example {
    private int a;
    private int b;
    private int c;
    private int d;
    private int e;

    // Builderは省略

    private Example(Builder builder) {
        this.a = builder.a;
        this.b = builder.b;
        this.c = builder.c;
        this.d = builder.d;
        this.e = builder.e;
    }
}

引数は先ほど作成したBuilderであり、そのフィールドをExampleフィールドに渡してあげます。
インナークラスなので、フィールドに直接アクセスしても大丈夫です。

そして、仕上げにBuilderにbuildメソッドを実装します。

public static class ExampleBuilder {
        private int a;
        private int b;
        private int c;
        private int d;
        private int e;

        public Builder a(int a) {
            this.a = a;
            return this;
        }

        public Builder b(int b) {
            this.b = b;
            return this;
        }
        //c, dは省略
        public Builder e(int e) {
            this.e = e;
            return this;
        }

        public Example build() {
            return new Example(this);
        }

    }

引数thisはBuilder自身なため、privateなコンストラクタにBuilderが渡されて、フィールドに値がセットされていれば、Exampleのフィールドに値がセットされます。

これを使用すると、Exampleを利用したいとき、

Example example = new Example.Builder.a(1).b(2).c(3).d(4).e(5).build();

とすることで、すべてのフィールドに値がセットされたExampleを取得できます。
一部にだけフィールドをセットするならば、

Example example = new Example.Builder.a(1).d(4).build();

と必要な値だけセットすれば大丈夫です。

何がうれしいのか

個人的に感じているBuilderメソッドのメリットはコンストラクタに渡すパラメータがわかりやくすなることだと思います。

コンストラクタに渡す引数が多くなると、その分見づらくなります。

Example example = new Example(int aaaaaa, int bbbbbbb, int ccccccc, int ddddddd, int eeeeeeee);


Builderパターンで実装しておけば、何をセットしているのか明示されているため、可読性が上がります。

また、optionalなパラメータな場合、使わないときはnullをいちいち渡さなければいけません。テレスコーピングコンストラクタパターンという、コンストラクタを複数用意してあげる方法もありますが、その分読みづらくなってしまします。
Builderパターンであれば、使わないパラメータはセットしなければ済む話なので、使う側が意識することが少なくてすみます。

終わりに

今回はEffective JavaのBuilderパターンについて書きましたが、GoFのBuilderパターンに関してもおいおい書いていきたいと思います。

参考

ジョシュア・ブロック 著 柴田 芳樹 訳 Effective Java 第二版

hatt0519
Android開発しています。
mixi
全ての人に心地よいつながりを
http://mixi.co.jp
Why not register and get more from Qiita?
  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
No 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
ユーザーは見つかりませんでした