概念:
將一個復雜對象的構建與它的表示分離。使得同樣構建過程可以創建不同表示
適用場景:
- 一個對象有很多屬性的情況下
- 想把復雜的對象創建和使用分離
優點:
封裝性好,擴展性好
詳解:
工廠模式注重把這個產品創造出來即可,而建造者更關心創建的細節,當創建一個對象需要使用很多步驟去完成的時候,我們可以考慮建造者模式,當創建一個對象比較簡單的時候,我們就可以使用工廠模式。通俗一點來理解,建造者模式更像是專門定做一個東西,還是拿上篇博客的例子來說,iterator()作為一個工廠方法,它是可以有不同的廠家,但是呢,它完成的都是遍歷的功能,而建造者更像是你買一個戒指,你不僅僅要求它能戴在手上,更加希望你的名字被刻在上面這樣。就是關注到產品細節的就可以用建造者模式。如果你還不理解,那我們來看下面的代碼:
class Test{ public static void main(String[] args) { StringBuilder s=new StringBuilder("你好").append(",我現在在研究").append("建造者模式").append("希望能有所收獲."); System.out.println(s); } }
運行結果如下:
上面可以鏈式調用append()方法,在UML圖(部分)里可以看見
拿其中一個append的方法就是
@Override public StringBuilder append(char c) { super.append(c); return this; }
StringBuilder的父類是AbstractStringBuilder抽象類。所以來到AbstractStringBuilder里面的append方法
@Override public AbstractStringBuilder append(char c) { ensureCapacityInternal(count + 1); value[count++] = c; return this; }
可以看見是要插入一個字符串,要先擴容,再在把這個值加入到value數組中。在這里多說一嘴,這也是StringBuilder,StringBuffer和String類最大的區別,在String底層是一個用final修飾的值不可變的數組,而AbstractStringBuilder中的數組是“值可變”的,下面是AbstractStringBuilder擴容的源碼
private void ensureCapacityInternal(int minimumCapacity) { // overflow-conscious code if (minimumCapacity - value.length > 0) { value = Arrays.copyOf(value, newCapacity(minimumCapacity)); } }
也就是原來的數組拷貝到一個新的長度數組里面。這雖然原來的數組也是不可變的,但是放在JVM底層StringBuilder是只改了這個對象指向的區域里面的值,並沒有改這個對象的指向區域。而String是直接new一個新對象,然后修改String舊對象指向的地方,來達到改值的操作。
總結:
扯遠了,現在回到建造者模式,建造者最常用的其實是想上面Test類中的鏈式調用,因為我可以訂做這個產品的具體細節,你再給我多少個append()或者一些其他方法調用,我返回的還是StringBuilder這個對象,也就是這個產品不變,但是里面的細節我有要求你給我做成什么樣的。可以和之前的工廠模式對比着看,會更有體會。