Java建造者設(shè)計模式詳解
建造者模式(Builder):將一個復(fù)雜對象的構(gòu)建與它的表示分離,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示。
使用場景:
- 當(dāng)創(chuàng)建復(fù)雜對象的算法應(yīng)該獨立于該對象的組成部分以及它們的裝配方式時。
- 當(dāng)構(gòu)造過程必須允許被構(gòu)造的對象有不同的表示時。
通用類圖:

舉例:我們生活當(dāng)中有許多設(shè)備都是以組裝的形式存在的,例如臺式電腦,那么有些廠商就會推出一些具有默認(rèn)配置的組裝電腦主機(jī)(這里可以用到模板方法模式來實現(xiàn)),顧客可以購買默認(rèn)配置的產(chǎn)品,也可以要求廠商重新組裝一部不同配置不同組裝方式的主機(jī)。此時,我們就可以使用建造者模式來滿足特殊顧客的要求了。
注意到這個例子中廠商是重新組裝一部主機(jī),即關(guān)注點是主機(jī)的每個組成部分,這就符合上面Builder模式給出的使用場景了。
簡單代碼實現(xiàn)如下:
//抽象產(chǎn)品類,使用了模板方法模式,不同產(chǎn)品有不同的“組成部分part”
abstract class AbstractProduct{
protected abstract void part01();
protected abstract void part02();
protected abstract void part03();
//模板方法給出了默認(rèn)的組裝方式,生成默認(rèn)的產(chǎn)品
public final AbstractProduct defaultProduct() {
part01();
part02();
part03();
return this;//返回當(dāng)前對象,即默認(rèn)組裝方式的產(chǎn)品
}
}
//具體的產(chǎn)品A、B,不同產(chǎn)品實現(xiàn)了不同的“組成部分part”
class ConcreteProductA extends AbstractProduct{
protected void part01() {
System.out.println("產(chǎn)品A :part01() ...");
}
protected void part02() {
System.out.println("產(chǎn)品A :part02() ...");
}
protected void part03() {
System.out.println("產(chǎn)品A :part03() ...");
}
}
class ConcreteProductB extends AbstractProduct{
protected void part01() {
System.out.println("產(chǎn)品B :part01() ...");
}
protected void part02() {
System.out.println("產(chǎn)品B :part02() ...");
}
protected void part03() {
System.out.println("產(chǎn)品B :part03() ...");
}
}
//抽象建造者,制定每一種產(chǎn)品應(yīng)該實現(xiàn)的組合方式buildPart()和生產(chǎn)buildProduct()的標(biāo)準(zhǔn)
abstract class AbstractBuilder{
public abstract void buildPart();
public abstract AbstractProduct buildProduct();
}
/*
* 具體建造者,如果對于默認(rèn)產(chǎn)品(即當(dāng)調(diào)用抽象產(chǎn)品中的defaultProduct()方法)不滿意時,
* 可以不調(diào)用它來獲得產(chǎn)品,而是使用具體的建造者來改變產(chǎn)品的生產(chǎn)組裝方式,以得到不同的產(chǎn)品
*/
class ConcreteBuilderA extends AbstractBuilder{
private AbstractProduct productA = new ConcreteProductA();
public void buildPart() {
this.productA.part03();
this.productA.part02();
this.productA.part01();
}
public AbstractProduct buildProduct() {
return this.productA;
}
}
class ConcreteBuilderB extends AbstractBuilder{
private AbstractProduct productB = new ConcreteProductB();
public void buildPart() {
this.productB.part02();
this.productB.part01();
//特地省略掉產(chǎn)品B中的一個組成部分,例如該部分的功能顧客不需要
// this.productB.part03();
}
public AbstractProduct buildProduct() {
return this.productB;
}
}
//導(dǎo)演類,預(yù)先持有各個產(chǎn)品的建造者,為需要不同于默認(rèn)產(chǎn)品的用戶提供不同的組裝方式
class Director{
private AbstractBuilder builderA = new ConcreteBuilderA();
private AbstractBuilder builderB = new ConcreteBuilderB();
public AbstractProduct getProductA() {
this.builderA.buildPart();
return this.builderA.buildProduct();
}
public AbstractProduct getProductB() {
this.builderB.buildPart();
return this.builderB.buildProduct();
}
}
//測試類
public class Client {
public static void main(String[] args) {
System.out.println("利用模板方法模式獲得默認(rèn)的產(chǎn)品A");
AbstractProduct defualtProductA = new ConcreteProductA().defaultProduct();
System.out.println("\n利用Director類獲得不同組裝方式的產(chǎn)品A");
Director director = new Director();
director.getProductA();
System.out.println("\n利用Director類獲得不同組裝方式的產(chǎn)品B");
director.getProductB();
}
}
測試結(jié)果:
利用模板方法模式獲得默認(rèn)的產(chǎn)品A
產(chǎn)品A :part01() ...
產(chǎn)品A :part02() ...
產(chǎn)品A :part03() ...
利用Director類獲得不同組裝方式的產(chǎn)品A
產(chǎn)品A :part03() ...
產(chǎn)品A :part02() ...
產(chǎn)品A :part01() ...
利用Director類獲得不同組裝方式的產(chǎn)品B
產(chǎn)品B :part02() ...
產(chǎn)品B :part01() ...
其實在這個例子當(dāng)中,產(chǎn)品類那一部分用到了上一篇文章講到的模板方法模式,即defaultProduct()提供了一個產(chǎn)品的默認(rèn)組成部分的組裝方式。
但是這里我有個疑問,AbstractProduct類中根據(jù)模板方法模式提供的的所謂默認(rèn)組裝方式只是打印出幾句測試的話而已,又不是真正返回一個具體產(chǎn)品,但是上面例子中那樣返回一個當(dāng)前對象(return this;)的處理方式不知道是否合理?
另外,在寫了這幾篇關(guān)于用Java代碼實現(xiàn)設(shè)計模式的文章之后,發(fā)現(xiàn)這個建造者Builder模式似乎是結(jié)合了抽象工廠模式、模板方法模式。上面一段已經(jīng)說過我的疑惑,至于抽象工廠模式,我個人是覺得上面代碼例子中的Director類就很類似抽象工廠的具體工廠類了,但是Director類還要負(fù)責(zé)build一下產(chǎn)品的組裝方式才返回一個產(chǎn)品,也許就是這個“build一下”才顯得建造者模式關(guān)注于產(chǎn)品各個部分的組裝,而抽象工廠模式僅僅只是關(guān)注于一個最終產(chǎn)品的生成。
之前看過一句話說大概是說:計算機(jī)方面的任何一個問題如果難以解決,都可以通過增加一個中間層來處理?,F(xiàn)在想了一下,好像Abstract Factory和Builder模式都是運用了這一“原理”來達(dá)到想要的效果。譬如Abstract Factory中有個抽象工廠類,Builder中有個Director類,說到底也就是封裝隱藏某些細(xì)節(jié),并從實現(xiàn)和使用這兩者之間解耦出來吧。
我認(rèn)為,一定要先理解了各個模式的關(guān)注點和適用場景之后才能更好地把握這些吧。
可能這幾個模式都是創(chuàng)建型的模式而且我沒有什么實戰(zhàn)經(jīng)驗才會使得我對于這些有點混淆了...不怕,在它們?nèi)繉崿F(xiàn)的過程中一點點思考,慢慢地運用到實際當(dāng)中去應(yīng)該就會逐漸明白的了。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所啟發(fā)。
相關(guān)文章
調(diào)用java.lang.Runtime.exec的正確姿勢分享
這篇文章主要介紹了調(diào)用java.lang.Runtime.exec的正確姿勢,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-11-11
SpringBoot整合Redis使用@Cacheable和RedisTemplate
本文主要介紹了SpringBoot整合Redis使用@Cacheable和RedisTemplate,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07
Springmvc conver實現(xiàn)原理及用法解析
這篇文章主要介紹了Springmvc conver實現(xiàn)原理及用法解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-10-10
解決Mybatis-plus找不到對應(yīng)表及默認(rèn)表名命名規(guī)則的問題
這篇文章主要介紹了解決Mybatis-plus找不到對應(yīng)表及默認(rèn)表名命名規(guī)則的問題,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-11-11
redis.clients.jedis.exceptions.JedisAskDataException異常解決
redis.clients.jedis.exceptions.JedisAskDataExceptio異常是在使用Jedis客戶端與Redis集群交互時遇到的一種重定向異常,本文就來介紹一下解決方法,感興趣的可以了解一下2024-05-05
解決Maven 項目報錯 java.httpservlet和synchronized使用方法
下面小編就為大家?guī)硪黄鉀QMaven 項目報錯 java.httpservlet和synchronized使用方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-07-07

