Builderパターンは、主に複雑なオブジェクトの作成のために、より複雑なオブジェクトの作成パターンです。この記事で紹介するのは、Directorの実装があるBuilderパターン、Directorの実装がないBuilderパターン、Lombokの実装です、
パターンの背景
なぜビルダーパターンが必要なのでしょうか?プロジェクトでは、より複雑なオブジェクトの作成があるかもしれません。たとえば、多数の他のオブジェクトの組み合わせの中にオブジェクトを作成するような場合です。これらのオブジェクトを作成するコードがユーザー側に書かれている場合、オブジェクトを使用するすべての場所は、明らかに十分にエレガントではない、巨大な長いコードを記述する必要があります!パブリックな繰り返しのコードは同じ場所で抽出されるべきであるという原則に沿って、このオブジェクトを作成する責任は抽出され、それを行うための特別なクラスに与えられるべきです!そこで、この目的のためにクリエイター・パターンが生まれました。
Builder パターンを使うと、生成のロジックを対応する Builder クラスの中に置くことができます。例えば、今フロントエンドはVOオブジェクトを返す必要があります。このVOオブジェクトはブラウザかモバイルかによって異なる構造型を返す必要がありますが、全体はおそらく同じ大きなVOオブジェクトです。このとき、2つのBuilderを作成することができます。1つはコンピュータ用のBuilder、もう1つはモバイル用のBuilderで、対応するBuilderをうまく書くだけで、後で使用するときにそのまま再利用できます。
UML
原則
ビルダーパターンは、つまり、複雑なオブジェクトを作成するロジックが実行するためにビルダークラスに抽出され、複雑なオブジェクトの構築と分離の彼の表現 。
繰り返しますが、このオブジェクトは複数の表現を必要とする可能性があるため、これらのビルダーは抽象化される必要があり、異なる表現を実現するためにビルダー実装クラスを拡張することが可能になります。
そして、異なるビルダー実装クラスのため、単に複雑なオブジェクトの様々な部分の特定の実装を担当し、複雑なオブジェクトにアセンブルする必要があります要件の順序:そのようなPart2、次にPart1、またはいくつかのケースは、Part2を組み立てる必要はありませんので、この時間は、アセンブリの順序を設定するには、ディレクタークラスを提供する必要があります。
クライアントはディレクターとやり取りするだけです。
もちろん、私が個人的に遭遇したほとんどのケースでは、Directorを削除して、ビルド処理をBuilder実装クラスに置くことができます。
しかし、これは建物の順序の要件は、より多くのアセンブリの順序の要件は、新しい注文の要件が発生するたびに、あなたは、オープンとクローズの原則に違反してビルダークラスを変更する必要がある場合は、あまりない場合です。
Builder パターンは Abstract Factory パターンと多少似ています:どちらもテンプレートに従ってオブジェクトの表現を構築します。違いは、Builder パターンが大きな複雑なオブジェクトを全体として構築して返すのに対し、Abstract Factory は一連の部分オブジェクトを返すことです。
ひつようじょうけん
- 構築する必要があるエンティティ・クラス。
- 抽象ビルダー
- インタフェースまたは抽象クラス;
- さまざまなビルダーを一様に制約します。buildPartX メソッドと getResult メソッドをアサートします。
- ビルダー実装クラス。
- 各部分に固有の実装ロジックを提供します。各 Builder 実装クラスは、ビジネス要件 Bean に対応する必要があります。
- Aビルダー
- 目的1: ビルドプロセスをクライアントから分離するため。
- 目的2: 複雑なオブジェクトをビルドするロジックを制御するため、ビルダーはすべてのメソッドを定義し、ディレクターはそれらを組み立てるための呼び出しを担当します。
実装
エンティティ
public class Car {
private String light;
private String wheel;
private String chair;
}
抽象クラスの構築
public abstract class CarBuilder {
/**
ここでCarオブジェクトを作成し、クラス継承を実装するだけである。
なぜCarオブジェクトがビルダーで作成されるかというと、Directorから隔離するためだろう。なぜなら、オブジェクト>Builder->Director中間に階層関係があるので、できるだけ各層を分離する。
*/
Car car = new Car();
public abstract void buildLight();
public abstract void buildWheel();
public abstract void buildChair();
/**これは静的メソッドであることができる*/
public Car createCar() {
return car;
}
}
特定のビルダーの実装
public class BigCarBuilder extends CarBuilder {
@Override
public void buildLight() {
this.car.setLight("big light");
}
@Override
public void buildWheel() {
this.car.setWheel("big wheel");
}
@Override
public void buildChair() {
this.car.setChair("big chair");
}
}
コマンドグループ
public class Director {
/** コンストラクタのパターンの2番目のキーポイント:
* Directorクラスは内部にビルダーを保持し、クライアントはどのビルダーがビルドに使用されるかを気にするだけでよい。
* こうすることで、クライアントはどのビルダーを使用しているかを知るだけでよくなり、ビルダーを初期化して、直接ディレクター・クラスに詰め込むことができる。*/
public CarBuilder builder;
public Director(CarBuilder builder) {
this.builder = builder;
}
public CarBuilder getBuilder() {
return builder;
}
/**オブジェクトを構築する*/
public Car build() {
builder.buildLight();
builder.buildWheel();
builder.buildChair();
return builder.createCar();
}
}
使う
CarBuilder builder = new BigCarBuilder();
//具体的にどのビルダーを使用してオブジェクトを構築するかは、設定ファイルを使用して構成することができ、柔軟性の程度を高める。
Director director = new Director(builder);
Car car = director.build();
System.out.println(car);
長所と短所
- 長所
- 責任の分担が薄いので、スケーラビリティが比較的高い。
- デメリット
- 複雑な構造、大量のコード、また、オブジェクトを作成するために一度にすべての拡張2ステップは非常に面倒であると感じていますか。
これは、上記の必要な条件をすべて実装したものです。オブジェクトの構築が複雑な場合でも、構造化のためにこのアプローチを使用することをお勧めします。
Directorの実装なし
とはいえ、場合によっては、DirectorクラスをBuilderに統合し、Directorの責任をBuilderに委ね、Builder自身に構築プロセスを同時に行わせることも可能です。
気付く
abstract class CarBuilder2 {
protected Car car = new Car();
public abstract void buildLight();
public abstract void buildWheel();
public abstract void buildChair();
/*builder自分で作る*/
public Car build() {
this.buildWheel();
this.buildChair();
this.buildLight();
return car;
}
}
public class NoDirectorCarBuilder extends CarBuilder2 {
@Override
public void buildLight() {
this.car.setLight("no director light");
}
@Override
public void buildWheel() {
this.car.setWheel("no director wheel");
}
@Override
public void buildChair() {
this.car.setChair("no director chair");
}
/* */
public static void main(String[] args) {
NoDirectorCarBuilder builder = new NoDirectorCarBuilder();
Car car = builder.build();
System.out.println(car);
}
}
これによってディレクター・クラスは単純化されますが、すべての責任をビルダーに委ねることになり、必然的にビルダーの責任が増えます。
しかし、オブジェクトの要件が非常に複雑な場合は、Directorのアプローチで構築することをお勧めします。 その方が拡張性があり、単一責任の原則に沿うからです。
Lombok
Javaの開発は、多くの場合、プラグインを使用します:@Builderアノテーションでlombokは非常に便利であったが、彼はまた、ビルダーパターンの使用です。オブジェクトを作成するには、このアノテーションを使用すると、まだ非常に便利です。その内部実装は次のとおりです:
class Person {
private String name;
private String age;
/*lombok */
/**
* キー4 オブジェクトを構築する
*/
public static PersonBuilder bulder() {
return new PersonBuilder();
}
/**
* キー1 コンストラクト
*/
public Person(PersonBuilder builder) {
this.name = builder.name;
this.age = builder.age;
}
/**
* キー2 クラスを構築する
*/
public static class PersonBuilder {
/**
* キー3プロパティコピー
*/
private String name;
private String age;
public PersonBuilder name(String name) {
this.name = name;
return this;
}
public PersonBuilder age(String age) {
this.age = age;
return this;
}
public Person build() {
return new Person(this);
}
}
public static void main(String[] args) {
Person p = Person.bulder().name("justin").age("24").build();
System.out.println(p.getName());
}
}
内部的には、元のクラスと同じプロパティを持つ現在のクラスの Builder クラスを作成し、ビルダーを通してプロパティに値を割り当てます。最後に、ビルダーのオブジェクトを使って元のクラスのオブジェクトを構築します。
長所と短所
全体として、ビルダー・パターンの長所と短所は以下の通り:
利点
- オブジェクトの作成と表現の分離は、デカップリングの考え方と一致しています。
- 各ビルダーは互いに独立しており、動的にビルダーを追加したり置き換えたりして、異なる表現を作成することができます。
- ある程度、複雑なオブジェクトを作成するロジックを明確に理解することができます。
デメリット
- 適用可能性とは、各コンポーネントがそれぞれ異なる表現を持っていることを除けば、おおよそ同じようなものです。違いが大きすぎてモデルに当てはまらない場合。
- 複雑なオブジェクトに対する要求が大きく変化すると、多くのビルドクラスが追加され、システムの複雑さが増します。
シナリオ
- 複雑なオブジェクトを構築します。
- 複雑なオブジェクトの外部表現は拡張可能である必要があり、製品がこの複雑なオブジェクトの表現に新たな要件を課す可能性があります。
- 生成された複雑なオブジェクト、オブジェクトの作成プロセス、内部オブジェクトは、相互依存関係を持っている、Directorの使用は非常に良いコントロールとこれらのシーケンスの理解を行うことができます。
添付ファイル
関連コード:
また、コードや記事に問題があれば修正してください!ありがとうございました!





