上一篇文章中學習了三種工廠模式,這篇文章來學習一下另外一種應用比較多的建立型模式,它適合用來建立擁有很是多的屬性的對象。一樣地,也是先從一個例子開始。java
相信小夥伴們在假期出去遊玩時,都會制定一套度假計劃。通常來講,須要包括以下幾個部分,VacationPlanner 類能夠以下定義:編程
public class VacationPlanner {
private int day; // 天數
private String city; // 旅遊城市
private int ticket; // 車票
private String hotel; // 住宿旅館
private String tourist; // 旅遊景點
private int personNum; // 人數
private String other; // 其餘
// setter/getter/toString
}
複製代碼
如此,咱們建立計劃的方法 createPlanner 能夠按照以下寫:設計模式
public class Vacation {
public VacationPlanner createPlanner(int day, String city, String hotel, int personNum, int ticket, String tourist, String other) {
VacationPlanner planner = new VacationPlanner();
planner.setDay(day);
planner.setCity(city);
planner.setHotel(hotel);
planner.setPersonNum(personNum);
planner.setTicket(ticket);
planner.setTourist(tourist);
planner.setOther(other);
return planner;
}
}
複製代碼
很簡單吧。可是若是不少人都想要製做一個度假計劃,而每一個人的計劃又不太同樣,因此,建立的度假計劃及其建立步驟也就不一樣。例如,有的人就是本地人,不須要旅館;有的人須要其餘活動。數組
另外,其實咱們並不須要知道度假計劃的內部實現。那咱們該如何作一個有彈性的設計,去適應各類變化呢?其實,咱們能夠建立一個單獨的建立者,將度假計劃的表示和建立計劃的步驟分開來。app
但在這以前,咱們應該定義一個抽象建造者,也就是要符合以前咱們所說的針對接口編程,而不是具體的類:ide
public abstract class AbstractVacationPlannerBuilder {
public abstract void buildDay();
public abstract void buildTicket();
public abstract void buildHotel();
public abstract void buildTourist();
public abstract void buildPersonNum();
public abstract void buildOther();
public abstract VacationPlanner getVacationPlanner();
}
複製代碼
而後,再來建立一個具體的建造者:學習
public class VacationPlannerBuilder extends AbstractVacationPlannerBuilder {
private VacationPlanner vacationPlanner = new VacationPlanner();
@Override
public void buildDay(int day) {
vacationPlanner.setDay(day);
}
@Override
public void buildTicket(int ticket) {
vacationPlanner.setTicket(ticket);
}
@Override
public void buildHotel(String hotel) {
vacationPlanner.setHotel(hotel);
}
@Override
public void buildTourist(String tourist) {
vacationPlanner.setTourist(tourist);
}
@Override
public void buildPersonNum(int personNum) {
vacationPlanner.setPersonNum(personNum);
}
@Override
public void buildOther(String other) {
vacationPlanner.setOther(other);
}
@Override
public VacationPlanner getVacationPlanner() {
return vacationPlanner;
}
}
複製代碼
如今 Vacation 就能夠按照以下的方式寫了:測試
public class Vacation {
private AbstractVacationPlannerBuilder builder;
public void setVacationPlannerBuilder(AbstractVacationPlannerBuilder builder) {
this.builder = builder;
}
public AbstractVacationPlannerBuilder createPlanner(int day, String city, String hotel, int personNum, int ticket, String tourist, String meal, String other) {
builder.buildDay(day);
builder.buildCity(city);
builder.buildHotel(hotel);
builder.buildPersonNum(personNum);
builder.buildTicket(ticket);
builder.buildTourist(tourist);
builder.buildOther(other);
return builder;
}
}
複製代碼
上述模式就是建造者模式,它是將一個複雜對象的表示和建立分離開來,容許經過多個步驟來建立對象,而且能夠改變其過程。ui
它的 UML 圖以下:this
下面來總結一下建造者模式的優勢:
缺點:
另外,建造者模式也可使用靜態內部類的形式,它是將實體類對應的 Builder 放置到實體類的內部,看一下它的代碼:
public class VacationPlanner {
private int day; // 天數
private String city; // 旅遊城市
private int ticket; // 車票
private String hotel; // 住宿旅館
private String tourist; // 旅遊景點
private int personNum; // 人數
private String other; // 其餘
// 全屬性的構造方法
public VacationPlanner(VacationPlannerBuilder builder) {
this.day = builder.day;
this.city = builder.city;
this.ticket = builder.ticket;
this.hotel = builder.hotel;
this.tourist = builder.tourist;
this.personNum = builder.personNum;
this.other = builder.other;
}
public static class VacationPlannerBuilder {
private int day; // 天數
private String city; // 旅遊城市
private int ticket; // 車票
private String hotel; // 住宿旅館
private String tourist; // 旅遊景點
private int personNum; // 人數
private String other; // 其餘
// 與以前不一樣,這裏返回 VacationPlannerBuilder
public VacationPlannerBuilder buildDay(int day) {
this.day = day;
return this;
}
public VacationPlannerBuilder buildCity(String city) {
this.city = city;
return this;
}
public VacationPlannerBuilder buildTicket(int ticket) {
this.ticket = ticket;
return this;
}
public VacationPlannerBuilder buildHotel(String hotel) {
this.hotel = hotel;
return this;
}
public VacationPlannerBuilder buildTourist(String tourist) {
this.tourist = tourist;
return this;
}
public VacationPlannerBuilder buildPersonNum(int personNum) {
this.personNum = personNum;
return this;
}
public VacationPlannerBuilder buildOther(String other) {
this.other = other;
return this;
}
public VacationPlanner build() {
return new VacationPlanner(this);
}
}
}
複製代碼
下面來寫個測試類進行測試:
public class Test {
public static void main(String[] args) {
VacationPlanner planner = new VacationPlanner.VacationPlannerBuilder()
.buildDay(3)
.buildCity("北京")
.buildHotel("7天")
.buildPersonNum(2)
.buildTicket(999)
.buildTourist("故宮")
.buildOther("其餘")
.build();
System.out.println(planner);
}
}
複製代碼
AbstractStringBuilder
能夠將 StringBuilder 當作 String 的建造者,而 AbstractStringBuilder 是建造者的抽象類。它的部分源碼以下:
abstract class AbstractStringBuilder implements Appendable, CharSequence {
// 存儲 char 字符的數組
char[] value;
int count;
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;
}
public AbstractStringBuilder append(int i) {
if (i == Integer.MIN_VALUE) {
append("-2147483648");
return this;
}
int appendedLength = (i < 0) ? Integer.stringSize(-i) + 1
: Integer.stringSize(i);
int spaceNeeded = count + appendedLength;
ensureCapacityInternal(spaceNeeded);
Integer.getChars(i, spaceNeeded, value);
count = spaceNeeded;
return this;
}
@Override
public abstract String toString();
}
複製代碼
StringBuilder
StringBuilder 的部分源碼以下,這裏使用的建造者模式是咱們以前看到的第一種模式:
public final class StringBuilder extends AbstractStringBuilder implements java.io.Serializable, CharSequence {
@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}
@Override
public StringBuilder append(int i) {
super.append(i);
return this;
}
@Override
public String toString() {
// 建立了一個新的 String
return new String(value, 0, count);
}
}
複製代碼
ImmutableSet 的建造者使用的是靜態內部類方式:
public abstract class ImmutableSet<E> extends ImmutableCollection<E> implements Set<E> {
public static <E> Builder<E> builder() {
return new Builder<E>();
}
public static class Builder<E> extends ImmutableCollection.ArrayBasedBuilder<E> {
@Override
public Builder<E> add(E element) {
super.add(element);
return this;
}
@Override
public Builder<E> addAll(Iterable<? extends E> elements) {
super.addAll(elements);
return this;
}
@Override
public ImmutableSet<E> build() {
ImmutableSet<E> result = construct(size, contents);
size = result.size();
return result;
}
}
private static <E> ImmutableSet<E> construct(int n, Object... elements) {
// 返回不一樣的 ImmutableSet 實現
}
}
複製代碼
通常它有兩種建立方法:
ImmutableSet<Object> set1 = new ImmutableSet.Builder<>().build();
ImmutableSet<Object> set2 = ImmutableSet.builder().build();
複製代碼