1.概念
定義:建造者模式是把一個物體的構造過程與其本身進行分離,使得相同的構造過程可以創建不同的物體,簡而言之,就是構造過程複用。
想象一下我們玩角色扮演類遊戲的時候,剛開始電腦會讓你創建角色,比如選擇人物的職業、頭髮顏色、性別,最後輸入一個騷氣的暱稱,這個創建的過程就算完成了!
2.爲什麼要用這個建造者模式呢
答:它是一種創建對象的軟件設計模式,旨在提高對象構造器的伸縮性。
不用這個模式,我們的對象伸縮性瓶頸是哪裏呢?看下面的代碼就會明白:
public Hero(Profession profession, String name) {
}
如您所見,構造函數參數的數量如果再增加,那麼很快就會失控,因爲同樣類型的參數,我們可能難以理解參數的排列。另外,如果將來想添加更多選項,則此參數列表可能會繼續增長。這也被稱爲伸縮構造函數反模式。
3.程式範例
還是以遊戲中創建英雄的例子來說吧,先來完成我們英雄的一些初始化屬性。
/**
* 職業的枚舉類
*
* @author suvue
* @date 2020/1/12
*/
public enum Profession {
/**
* 戰士
*/
WARRIOR,
/**
* 刺客
*/
THIEF,
/**
* 法師
*/
MAGE,
;
@Override
public String toString() {
return name().toLowerCase();
}
}
下面是英雄的頭髮顏色枚舉。
/**
* 頭髮顏色
*
* @author suvue
* @date 2020/1/12
*/
public enum HairColor {
/**
* 紅髮
*/
RED,
/**
* 棕發
*/
BROWN,
/**
* 黑髮
*/
BLACK,
;
@Override
public String toString() {
return name().toLowerCase();
}
}
下面是英雄持有的武器枚舉了。
import lombok.Data;
/**
* 英雄
*
* @author suvue
* @date 2020/1/12
*/
@Data
public class Hero {
private final HairColor hairColor;
private final Profession profession;
private final Weapon weapon;
private final String name;
/**
* 我們傳進來一個通用的建造器
*/
public Hero(Builder builder) {
this.hairColor = builder.hairColor;
this.profession = builder.profession;
this.weapon = builder.weapon;
this.name = builder.name;
}
/**
* 這是一個靜態內部類,我們來實現這個通用建造器
*/
public static class Builder {
private HairColor hairColor;
private final Profession profession;
private Weapon weapon;
private final String name;
/**
* 建造器的構造函數 我們要求職業和暱稱必填
*/
public Builder(Profession profession, String name) {
if (profession == null || name == null) {
throw new IllegalArgumentException("初始化參數爲空");
}
this.profession = profession;
this.name = name;
}
public Builder withHairColor(HairColor hairColor) {
this.hairColor = hairColor;
return this;
}
public Builder withWeapon(Weapon weapon) {
this.weapon = weapon;
return this;
}
public Hero build() {
return new Hero(this);
}
}
}
我們來看看具體是怎麼使用的吧
public class Client {
public static void main(String[] args) {
//創建一個拿着法杖的紅髮魔法師角色
Hero mage = new Hero
.Builder(Profession.MAGE, "法師")
.withHairColor(HairColor.RED)
.withWeapon(Weapon.ROD)
.build();
System.out.println(mage.toString());
//創建一個拿着劍的黑髮戰士角色
Hero warrior = new Hero.Builder(Profession.WARRIOR, "戰士")
.withHairColor(HairColor.BLACK)
.withWeapon(Weapon.SWORD)
.build();
System.out.println(warrior.toString());
}
}
創建過程是不是很簡單呢,而且以後要是擴展的話,直接在Hero類中加一個類似於withWeapon()的方法就行啦
前輩們總結的經驗,都乃是精髓呀!
4.建造者模式在框架中的使用
4.1JDK1.8源碼中的建造者模式
StringBuilder與StringBuffer的父抽象類:AbstractStringBuilder 我們截取一部分關鍵源碼看一下。
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}
4.2 spring中的建造者模式
摘選 BeanDefinitionBuilder 類的部分源碼。
package org.springframework.beans.factory.support;
public final class BeanDefinitionBuilder {
//獲取builder對象的靜態方法
public static BeanDefinitionBuilder genericBeanDefinition() {
return new BeanDefinitionBuilder(new GenericBeanDefinition());
}
public BeanDefinitionBuilder setParentName(String parentName) {
this.beanDefinition.setParentName(parentName);
return this;
}
public BeanDefinitionBuilder setFactoryMethod(String factoryMethod) {
this.beanDefinition.setFactoryMethodName(factoryMethod);
return this;
}
public BeanDefinitionBuilder setFactoryMethodOnBean(String factoryMethod, String factoryBean) {
this.beanDefinition.setFactoryMethodName(factoryMethod);
this.beanDefinition.setFactoryBeanName(factoryBean);
return this;
}
//可以有很多個set方法靈活性的爲屬性賦值
//...
}