目的
將複雜對象的構建
與表示
分離,達到同樣構建過程能夠得到不同的表示。
說明
現實例子
角色扮演遊戲中的角色構建,通過選擇職業、性別、髮型等屬性構建自己的角色,構建過程一致,卻得到不同的角色。
講人話
允許你在不污染構造方法的前提下,構建一個類的不同風格的實例。
維基百科
建造者模式是爲解決
可伸縮構造器反模式
(telescoping constructor anti-patter)的一種對象創建型軟件設計模式
構造器反模式,某一時間點我們有如下的一個構造器
public Hero(Profession profession, String name,
HairType hairType, HairColor hairColor,
Armor armor, Weapon weapon) {
// ...
}
如上所示,構造器的參數很多且很難理解參數的排列順序。當需要添加屬性時,參數還會繼續增長。
編程樣例
手工打造
通過手寫代碼方式實現建造者模式
- 實體類+建造者類
package design.creational.builder;
/**
* 角色類
*
* @author faith.huan 2019-11-28 21:45
*/
public class Hero {
/**
* 暱稱
*/
private String name;
/**
* 種族
*/
private String race;
/**
* 職業
*/
private String profession;
/**
* 髮型
*/
private String hairType;
/**
* 髮色
*/
private String hairColor;
/**
* 膚色
*/
private String skinColor;
public Hero(HeroBuilder builder) {
this.name = builder.name;
this.race = builder.race;
this.profession = builder.profession;
this.hairType = builder.hairType;
this.hairColor = builder.hairColor;
this.skinColor = builder.skinColor;
}
/**
* 得到建造者HeroBuilder
*/
public static HeroBuilder builder() {
return new HeroBuilder();
}
@Override
public String toString() {
return "Hero{" +
"name='" + name + '\'' +
", race='" + race + '\'' +
", profession='" + profession + '\'' +
", hairType='" + hairType + '\'' +
", hairColor='" + hairColor + '\'' +
", skinColor='" + skinColor + '\'' +
'}';
}
/**
* 建造者類
*/
public static class HeroBuilder {
private String name;
private String race;
private String profession;
private String hairType;
private String hairColor;
private String skinColor;
public HeroBuilder withName(String name) {
this.name = name;
return this;
}
public HeroBuilder withRace(String race) {
this.race = race;
return this;
}
public HeroBuilder withProfession(String profession) {
this.profession = profession;
return this;
}
public HeroBuilder withHairType(String hairType) {
this.hairType = hairType;
return this;
}
public HeroBuilder withHairColor(String hairColor) {
this.hairColor = hairColor;
return this;
}
public HeroBuilder withSkinColor(String skinColor) {
this.skinColor = skinColor;
return this;
}
public Hero build() {
return new Hero(this);
}
}
}
- 測試類
package design.creational.builder;
/**
* 角色類測試
*
* @author faith.huan 2019-11-28 22:05:22
*/
public class HeroTest {
public static void main(String[] args) {
Hero hero = Hero.builder().withName("夕日之殤")
.withRace("人族")
.withProfession("青雲門")
.withHairType("飄逸髮型")
.withHairColor("深空灰")
.withSkinColor("亮銀色")
.build();
System.out.println(hero);
}
}
測試結果
Lombok版本
通過上面手寫建造者模式的例子發現構建過程比較清爽,然而建造者手寫有點複雜,21世紀了還是要藉助下高科技比較好,下面展示如何使用Lombok完成上面的建造者例子
package design.creational.builder;
import lombok.Builder;
import lombok.ToString;
/**
* 使用Lombok完成建造者示例
*
* @author faith.huan 2019-11-28 22:14:01
*/
@Builder
@ToString
public class HeroLombok {
/**
* 暱稱
*/
private String name;
/**
* 種族
*/
private String race;
/**
* 職業
*/
private String profession;
/**
* 髮型
*/
private String hairType;
/**
* 髮色
*/
private String hairColor;
/**
* 膚色
*/
private String skinColor;
}
額…簡單的好像令人髮指,通過5分鐘手寫的建造者代碼,通過Lombok的一個註解@Builder寫完了
- 測試代碼
package design.creational.builder;
/**
* 角色類測試
*
* @author faith.huan 2019-11-28 22:05:22
*/
public class HeroLombokTest {
public static void main(String[] args) {
HeroLombok heroLombok = HeroLombok.builder().name("夕日之殤")
.race("人族")
.profession("青雲門")
.hairType("飄逸髮型")
.hairColor("深空灰")
.skinColor("亮銀色")
.build();
System.out.println(heroLombok);
}
}
測試結果
從測試結果看手寫的建造者與Lombok生成的建造者都能完成角色構建。
適用性
- 創建複雜對象的算法應獨立於組成對象的零件及其組裝方式
- 構造過程必須允許所構造的對象具有不同的表示形式
真實例子
- java.lang.StringBuilder
- java.nio.ByteBuffer as well as similar buffers such as FloatBuffer, IntBuffer and so on.
- java.lang.StringBuffer
- All implementations of java.lang.Appendable
- Apache Camel builders
- Apache Commons Option.Builder
參考
https://github.com/iluwatar/java-design-patterns/tree/master/builder