堆積木,建造者模式
0x01:建造者模式簡(jiǎn)介
將一個(gè)復(fù)雜對(duì)象的構(gòu)建與它的表示分離,使得同樣的構(gòu)建過(guò)程可以創(chuàng)建不同的表示。
假如一個(gè)對(duì)象的構(gòu)建很復(fù)雜,需要很多步驟。則可以使用建造者模式,將其構(gòu)建對(duì)象和組裝成一個(gè)對(duì)象這兩步給分開(kāi)來(lái)。構(gòu)建部分為(Builder)和組織部分(Director),實(shí)現(xiàn)了構(gòu)建和裝配的解耦。

主要角色如下:
Builder:為創(chuàng)建一個(gè)產(chǎn)品對(duì)象的各個(gè)部件指定抽象接口,一般由子類實(shí)現(xiàn);
ConcreteBuilder:具體建造者,實(shí)現(xiàn)抽象類定義的所有方法,并且返回一個(gè)組建好的產(chǎn)品對(duì)象;
Director:為指揮者 / 導(dǎo)演類,負(fù)責(zé)安排已有模塊的組裝順序,然后告訴Builder開(kāi)始建造;
Product:表示被構(gòu)造的復(fù)雜對(duì)象。ConcreteBuilder創(chuàng)建該產(chǎn)品的內(nèi)部表示并定義它的裝配過(guò)程,包含定義組成部件的類,包括將這些部件裝配成最終產(chǎn)品的接口。
0x02:建造者模式實(shí)現(xiàn)
Product:要被構(gòu)建的產(chǎn)品
public?class?Product?{
????private?List?parts?=?new?ArrayList();
????public?void?addPart(String?part)?{
????????parts.add(part);
????}
????public?void?show(){
????????if(!parts.isEmpty()){
????????????parts.forEach(e?->?{
????????????????System.out.println(?e?);
????????????});
????????}
????}
}
Director:調(diào)用具體建造者進(jìn)行產(chǎn)品構(gòu)建
public?class?Director?{
????public?void?construct(Builder?builder)?{
????????builder.buildPartA();
????????builder.buildPartB();
????}
}
Builder:建造者抽象接口
public?interface?Builder?{
?????void?buildPartA();????????//產(chǎn)品的A部件
?????void?buildPartB();????????//產(chǎn)品的B部件
?????Product?getResult();????//組裝產(chǎn)品建造后的結(jié)果
}
具體建造者ConcreteBuilder:有幾個(gè)產(chǎn)品類就有幾個(gè)具體的建造者,而且這多個(gè)產(chǎn)品類具有相同的接口或抽象類。
public?class?ConcreteBuilder1?implements?Builder?{
????private?Product?product?=?new?Product();
????//設(shè)置產(chǎn)品零件
????@Override
????public?void?buildPartA()?{
????????product.addPart("ConcreteBuilder1>>部件A");
????}
????@Override
????public?void?buildPartB()?{
????????product.addPart("ConcreteBuilder1>>部件B");
????}
????//組建一個(gè)產(chǎn)品
????@Override
????public?Product?getResult()?{
????????return?product;
????}
}
public?class?ConcreteBuilder2?implements?Builder?{
????private?Product?product?=?new?Product();
????//設(shè)置產(chǎn)品零件
????@Override
????public?void?buildPartA()?{
????????product.addPart("ConcreteBuilder2>>部件A");
????}
????@Override
????public?void?buildPartB()?{
????????product.addPart("ConcreteBuilder2>>部件B");
????}
????//組建一個(gè)產(chǎn)品
????@Override
????public?Product?getResult()?{
????????return?product;
????}
}
建造者模式測(cè)試代碼
public?class?Client?{
????public?static?void?main(String[]?args)?{
????????Director?director?=?new?Director();
????????Builder?builder1?=?new?ConcreteBuilder1();
????????Builder?builder2?=?new?ConcreteBuilder2();
????????//指揮者用ConcreteBuilder1的方法來(lái)建造產(chǎn)品
????????director.construct(builder1);
????????Product?product1?=?builder1.getResult();
????????product1.show();
????????//指揮者用ConcreteBuilder2的方法來(lái)建造產(chǎn)品
????????director.construct(builder2);
????????Product?product2?=?builder2.getResult();
????????product2.show();
????}
}
可以看出建造者模式具有以下特點(diǎn):
良好的封裝性:建造者對(duì)客戶端屏蔽了產(chǎn)品內(nèi)部組成的細(xì)節(jié),客戶端不用關(guān)心每一個(gè)具體的產(chǎn)品內(nèi)部是如何實(shí)現(xiàn)的。
符合開(kāi)閉原則
便于控制細(xì)節(jié)風(fēng)險(xiǎn):由于建造者是相互獨(dú)立的,因此可以對(duì)建造過(guò)程逐步細(xì)化,而不對(duì)其他的模塊產(chǎn)生任何影響。
0x03:建造者模式在JDK中運(yùn)用
在JDK中,最經(jīng)典的建造者模式的運(yùn)用是StringBuilder和StringBuffer,這兩個(gè)類最主要的區(qū)別就是StringBuilder線程不安全,StringBuffer線程安全。下面與StringBuilder源碼講解一下,建造者模式在JDK中的運(yùn)用。
Appendable 接口定義了多個(gè) append 方法(抽象方法),即 Appendable 為抽象建造者(Builder),定義了抽象方法
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 實(shí)現(xiàn)了 Appendable 接口方法所有append()方法,儼然AbstractStringBuilder 已經(jīng)是就建造者,只是是一個(gè)抽象類AbstractStringBuilder?,不能實(shí)例化
abstract?class?AbstractStringBuilder?implements?Appendable,?CharSequence?{
????@Override
????public?AbstractStringBuilder?append(CharSequence?s)?{
????????if?(s?==?null)
????????????return?appendNull();
????????if?(s?instanceof?String)
????????????return?this.append((String)s);
????????if?(s?instanceof?AbstractStringBuilder)
????????????return?this.append((AbstractStringBuilder)s);
????????return?this.append(s,?0,?s.length());
????}
????@Override
????public?AbstractStringBuilder?append(CharSequence?s,?int?start,?int?end)?{
????????if?(s?==?null)
????????????s?=?"null";
????????if?((start?0)?||?(start?>?end)?||?(end?>?s.length()))
????????????throw?new?IndexOutOfBoundsException(
????????????????"start?"?+?start?+?",?end?"?+?end?+?",?s.length()?"
????????????????+?s.length());
????????int?len?=?end?-?start;
????????ensureCapacityInternal(count?+?len);
????????for?(int?i?=?start,?j?=?count;?i?????????????value[j]?=?s.charAt(i);
????????count?+=?len;
????????return?this;
????}
???@Override
????public?AbstractStringBuilder?append(char?c)?{
????????ensureCapacityInternal(count?+?1);
????????value[count++]?=?c;
????????return?this;
????}
????//?省略
}
StringBuilder 既充當(dāng)了指揮者角色(Director),同時(shí)也充當(dāng)了具體的建造者(ConcreteBuilder),建造方法的實(shí)現(xiàn)是由 AbstractStringBuilder 完成,而 StringBuilder 繼承了 AbstractStringBuilder
public?final?class?StringBuilder
????extends?AbstractStringBuilder
????implements?java.io.Serializable,?CharSequence
{
???@Override
????public?StringBuilder?append(String?str)?{
????????super.append(str);
????????return?this;
????}
????//其他省略
}
從StringBuilder代碼上看,大部分方法都繼承與AbstractStringBuilder,雖然是重寫(xiě),但是還是直接調(diào)用了AbstractStringBuilder類中非方法,只是返回對(duì)象不太一樣,StringBuilder類返回的對(duì)象就是當(dāng)前創(chuàng)建的對(duì)象this本身(Product)。
另外,MyBatis框架中也大量使用建造者模式,如果想了解MyBatis框架中什么運(yùn)用建造者模式的,可以閱讀下MyBatis的源碼。

喜歡,在看
