設計模式系列—建造者模式
前言
- 23種設計模式速記
 - 單例(singleton)模式
 - 工廠方法(factory method)模式
 - 抽象工廠(abstract factory)模式
 
23種設計模式快速記憶的請看上面第一篇,本篇和大家一起來學習建造者模式相關內容。
模式定義
將一個復雜對象的創(chuàng)建與他的表示分離,使得同樣的構建過程可以創(chuàng)建不同的表示。
用戶只需要給出指定復雜對象的類型和內容;
建造者模式負責按順序創(chuàng)建復雜對象(把內部的建造過程和細節(jié)隱藏起來)
解決的問題
- 降低創(chuàng)建復雜對象的復雜度
 - 隔離了創(chuàng)建對象的構建過程 & 表示
 
從而:
- 方便用戶創(chuàng)建復雜的對象(不需要知道實現(xiàn)過程)
 - 代碼復用性 & 封裝性(將對象構建過程和細節(jié)進行封裝 & 復用)
 
模式組成
- 指揮者(Director)直接和客戶(Client)進行需求溝通;
 - 溝通后指揮者將客戶創(chuàng)建產品的需求劃分為各個部件的建造請求(Builder);
 - 將各個部件的建造請求委派到具體的建造者(ConcreteBuilder);
 - 各個具體建造者負責進行產品部件的構建;
 - 最終構建成具體產品(Product)。
 
實例說明
實例概況
- 背景 小張希望去中關村買一臺組裝的臺式主機
 - 過程
 
- 中關村老板(Diretor)和小張(Client)進行需求溝通(買來打游戲?學習?看片?)
 - 了解需求后,電腦城老板將小張需要的主機劃分為各個部件(Builder)的建造請求(CPU、主板......)
 - 指揮裝機人員(ConcreteBuilder)去構建組件;
 - 將組件組裝起來成小張需要的電腦(Product)
 
使用步驟
步驟1:定義具體產品類(Product):電腦
- class Computer{
 - //電腦組件的集合
 - private List<String> parts = new ArrayList<String>();
 - //用于將組件組裝到電腦里
 - public void Add(String part){
 - parts.add(part);
 - }
 - public void Show(){
 - for (int i = 0;i<parts.size();i++){
 - System.out.println("組件" + parts.get(i) + "裝好了");
 - }
 - System.out.println("電腦組裝完成,請驗收");
 - }
 - }
 
步驟2:定義組裝的過程(Builder):組裝電腦的過程
- abstract class Builder {
 - //第一步:裝CPU
 - //聲明為抽象方法,具體由子類實現(xiàn)
 - public abstract void BuildCPU();
 - //第二步:裝主板
 - //聲明為抽象方法,具體由子類實現(xiàn)
 - public abstract void BuildMainboard();
 - //第三步:裝硬盤
 - //聲明為抽象方法,具體由子類實現(xiàn)
 - public abstract void BuildHD();
 - //返回產品的方法:獲得組裝好的電腦
 - public abstract Computer GetComputer();
 - }
 
步驟3: 中關村老板委派任務給裝機人員(Director)
- class Director{
 - //指揮裝機人員組裝電腦
 - public void Construct(Builder builder){
 - builder. BuildCPU();
 - builder.BuildMainboard();
 - builder.BuildHD();
 - }
 - }
 
步驟4: 創(chuàng)建具體的建造者(ConcreteBuilder):裝機人員
- class ConcreteBuilder extends Builder{
 - //創(chuàng)建產品實例
 - Computer computer = new Computer();
 - //組裝產品
 - @Override
 - public void BuildCPU(){
 - computer.Add("組裝CPU");
 - }
 - @Override
 - public void BuildMainboard() {
 - computer.Add("組裝主板");
 - }
 - @Override
 - public void BuildHD() {
 - computer.Add("組裝主板");
 - }
 - //返回組裝成功的電腦
 - @Override
 - public Computer GetComputer(){
 - return computer;
 - }
 - }
 
步驟5:客戶端調用-小張到電腦城找老板買電腦
- public class BuilderPattern<builder> {
 - public static void main(String[] args) {
 - // 步驟5:客戶端調用-小張到電腦城找老板買電腦
 - //逛了很久終于發(fā)現(xiàn)一家合適的電腦店
 - //找到該店的老板和裝機人員
 - Director director = new Director();
 - Builder builder = new ConcreteBuilder();
 - //溝通需求后,老板叫裝機人員去裝電腦
 - director.Construct(builder);
 - //裝完后,組裝人員搬來組裝好的電腦
 - Computer computer = builder.GetComputer();
 - //組裝人員展示電腦給小張看
 - computer.Show();
 - }
 - }
 
輸出結果
- 組件CPU裝好了
 - 組件主板裝好了
 - 組件硬盤裝好了
 - 電腦組裝完成,請驗收
 
優(yōu)點
- 良好的封裝性:建造者對客戶端屏蔽了產品內部組成的細節(jié),客戶端不用關心每一個具體的產品內部是如何實現(xiàn)的。
 - 符合開閉原則
 - 便于控制細節(jié)風險:由于建造者是相互獨立的,因此可以對建造過程逐步細化,而不對其他的模塊產生任何影響。
 
每一個具體建造者都相對獨立,而與其他的具體建造者無關,因此可以很方便地替換具體建造者或增加新的具體建造者,用戶使用不同的具體建造者即可得到不同的產品對象。
缺點
- 建造者模式所創(chuàng)建的產品一般具有較多的共同點,其組成部分相似;如果產品之間的差異性很大,則不適合使用建造者模式,因此其使用范圍受到一定的限制。
 - 如果產品的內部變化復雜,可能會導致需要定義很多具體建造者類來實現(xiàn)這種變化,導致系統(tǒng)變得很龐大。
 
應用場景
- 需要生成的對象具有復雜的內部結構
 - 需要生成的對象內部屬性本身相互依賴
 - 與不可變對象配合使用
 
與工廠方法模式的區(qū)別
建造者模式最主要的功能是基本方法的調用順序安排,基本方法已經實現(xiàn),我們可以理解為零件的裝配,順序不同產生的對象也不同;而工廠方法的注重點是創(chuàng)建,創(chuàng)建零件是其主要職責,不關心組裝順序。
源碼中的應用
- # jdk
 - java.lang.StringBuilder
 - # Spring源碼
 - org.springframework.web.servlet.mvc.method.RequestMappingInfo
 - org.springframework.beans.factory.support.BeanDefinitionBuilder
 - ......
 
StringBuilder源碼分析
在jdk中StringBuilder類的實現(xiàn)中,采用建造者模式的思想。具體分析如下:
StringBuilder類繼承自AbstractStringBuilder,而AbstractStringBuilder實現(xiàn)了Appendable接口。AbstractStringBuilder雖然是一個抽象類,但是它實現(xiàn)了Appendable接口中的各個append()方法,因此在這里Appendable接口是一個抽象建造者,而AbstractStringBuilder是建造者,只是不能實例化。對于StringBuilder類,它既充當了指揮者角色,同時充當了具體的建造者,建造方法的具體實現(xiàn)是由AbstractStringBuilder完成,StringBuilder繼承了AbstractStringBuilder。
Appendable接口
- public interface Appendable {
 - Appendable append(CharSequence csq) throws IOException;
 - Appendable append(CharSequence csq, int start, int end) throws IOException;
 - Appendable append(char c) throws IOException;
 - }
 
AbstractStringBuilder類
- abstract class AbstractStringBuilder implements Appendable, CharSequence {
 - char[] value;//The value is used for character storage.
 - int count;//The count is the number of characters used.
 - AbstractStringBuilder() { }
 - AbstractStringBuilder(int capacity) {
 - value = new char[capacity];
 - }
 - 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;
 - }
 - private AbstractStringBuilder appendNull() {
 - int c = count;
 - ensureCapacityInternal(c + 4);
 - final char[] value = this.value;
 - value[c++] = 'n';
 - value[c++] = 'u';
 - value[c++] = 'l';
 - value[c++] = 'l';
 - count = c;
 - return this;
 - }
 - private void ensureCapacityInternal(int minimumCapacity) {
 - // overflow-conscious code
 - if (minimumCapacity - value.length > 0) {
 - value = Arrays.copyOf(value,
 - newCapacity(minimumCapacity));
 - }
 - }
 - public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
 - if (srcBegin < 0) {
 - throw new StringIndexOutOfBoundsException(srcBegin);
 - }
 - if (srcEnd > value.length) {
 - throw new StringIndexOutOfBoundsException(srcEnd);
 - }
 - if (srcBegin > srcEnd) {
 - throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
 - }
 - System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
 - }
 - // 此次省略......
 - }
 
StringBuilder類:
- public final class StringBuilder extends AbstractStringBuilder implements java.io.Serializable, CharSequence {
 - //雖說是重寫,但還是調用的AbstractStringBuilder方法
 - @Override
 - public StringBuilder append(String str) {
 - super.append(str);
 - return this;
 - }
 - }
 
PS:以上代碼提交在 Github :
https://github.com/Niuh-Study/niuh-designpatterns.git




















 
 
 










 
 
 
 