Builderパターンってどんなパターン?
複雑な手順でオブジェクトを生成する場合に使えるパターンになります。
メリット
通常のコンストラクタの初期化処理では出来ない、複雑な初期化処理ができます。
例えば、数多くの初期化パラメータを組み合わせて、少し性質の異なるオブジェクトをたくさん生成したい場合等に使えます。
コンストラクタの数が増やせばいいのでは?
例えば、下記のように色んなケースのコンストラクタを増やせば、わざわざデザインパターンなんて、使わなくても複雑な初期化処理ができそうな気がします。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public class ConstractaTest { /* 引数1コンストラクタ */ ConstractaTest(String param){ } /* 引数2コンストラクタ */ ConstractaTest(String param,int param2){ } /* 引数5コンストラクタ */ ConstractaTest(String param,int param2,int param3,int param4,int param5){ } } |
しかし、これだと下記のデメリットがあります。
- それだとコンストラクタの数が増えすぎる。
- 開発者が側がどのコンストラクタを選べばよいか選定が難しい。
- コンストラクタ引数の数が増減した際に、コンストラクタのメンテナンスが大変。
どのようなクラス設計か?
あらかじめ正しい生成手順を決めた複数のメソッドを専用にまとめたクラス呼ぶことで、1つのオブジェクトを生成させます。
要は、「コンストラクタのようなクラスを作る」という表現が一番理解にしっくりくるポイントかもしれません。
実装時時に必要なクラス
実装時は、「ビルダクラス」、「ディレクタクラス」の二つを実装することが通常です。
ビルダクラス
通常のクラスで言えば、コンストラクタを分割したメソッドを持つクラスです。
ディレクタクラス
ビルダクラスの素材を使って、どのような手順で初期化するかを定義するクラスです。
実際に実装してみる。
クラス図で整理すると下記のような感じです。
Main.java(メインプログラム)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
package Builder; public class Main { public static void main(String args[]) { AisatuBuilder aisatuBuild = new AisatuBuilder(); //下から上への挨拶 SitaToUe stu = new SitaToUe(); Aisatu aisatu = stu.createAisatu(aisatuBuild); System.out.println("下から上への挨拶:" + aisatu.gendo); //上から下への挨拶 UeToSita uts = new UeToSita(); Aisatu aisatu2 = uts.createAisatu(aisatuBuild); System.out.println("上から下への挨拶:" + aisatu2.gendo); } } |
Aisatu.java(通常のクラス:このクラスが持つフィールドを複雑な手順で初期化したい)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
package Builder; /** * 挨拶に関するクラス * */ public class Aisatu { /* 挨拶の言動 */ String gendo; Aisatu(String gendo){ this.gendo = gendo; } } |
AisatuBuilder.java(ビルダクラス:コンストラクタを分割したメソッドを多数持つ。)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
package Builder; /** * 挨拶の言動を生成するクラス */ public class AisatuBuilder { /* 言動 */ String gendo; /* コンストラクタ */ AisatuBuilder(){ this.gendo = ""; } /* 上から下への挨拶 */ void ueTositaMessage() { gendo += "「おす」"; } /* 上から下への挨拶 */ void sitaToUeMessage() { gendo += "「おはようございます!」"; } /* 上から下への挨拶の態度 */ void ueTositaTaido() { gendo += "と目を見ずにする。"; } /* 上から下への挨拶 */ void sitaToUeTaido() { gendo += "と目を見て元気良くする。"; } Aisatu getAisatu() { Aisatu aisatuBuildResult = new Aisatu(gendo); gendo = ""; return aisatuBuildResult; } } |
SitaToUe.java(ディレクタクラス1:初期化手順を持つ)
1 2 3 4 5 6 7 8 9 10 11 |
package Builder; public class SitaToUe { Aisatu createAisatu(AisatuBuilder build) { build.sitaToUeMessage(); build.sitaToUeTaido(); return build.getAisatu(); } } |
UeToSita.java(ディレクタクラス2:初期化手順を持つ)
1 2 3 4 5 6 7 8 9 |
package Builder; public class UeToSita { Aisatu createAisatu(AisatuBuilder build) { build.ueTositaMessage(); build.ueTositaTaido(); return build.getAisatu(); } } |
この記事へのコメントはありません。