一、定義
將一個複雜對象的構造與它的表示分離,使同樣的構建過程可以創建不同的表示,這樣的設計模式被稱爲建造者模式。
二、使用範圍
1.創建一個複雜的對象,他有多個不同的模塊組成,其中有些模塊不會改變,但是其他模塊可能經常發生改變,我們不得已需要把不變的模塊與常變的模塊分開實現時。
2.當構造過程必須允許被構造的對象有不同表示時。
三、功能實現角色
1.builder:爲創建一個產品對象的各個部件指定抽象接口。
2.ConcreteBuilder:實現Builder的接口以構造和裝配該產品的各個部件,定義並明確它所創建的表示,並 提供一個檢索產品的接口。
3.Director:構造一個使用Builder接口的對象。
4.Product:表示被構造的複雜對象。ConcreteBuilder創建該產品的內部表示並定義它的裝配過程,包含定義組成部件的類,包括將這些部件裝配成最終產品的接口。
四、實踐
1.情景假設
我們在計費的過程中有一個計費模式獲取類,他的功能是獲取當前這個用戶所需要的計費模式,但是計費有很多種,比如SMS計費(短信計費)、Cash計費(銀行卡計費),其中SMS計費又包括中國移動、中國聯通、印尼Tsel、印尼isat計費,Cash包括招商銀行、農行、印尼Visa等,且不同支付方式給予不同的計費點和訂單開頭。在國外用戶和國內用戶時,要提供不同的計費集。
2.當前計費信息接口
public interface FeeInterf {
public String orderNo();//當前交易編號
public FeeTypeInterf feeType();//當前交易類型
public float price();//當前交易金額
}
3.當前計費類型接口
public interface FeeTypeInterf {
public String feeType();
}
4.當前計費類型的實現類
SMSFeeType
import cn.yzstu.buldermodule.interf.FeeTypeInterf;
/**
* 類描述
*
* @author: 12405
* @date: 2020/3/25-22:28
*/
public class SMSFeeType implements FeeTypeInterf {
@Override
public String feeType() {
return "SMS";
}
}
CashFeeType
import cn.yzstu.buldermodule.interf.FeeTypeInterf;
/**
* 類描述
*
* @author: 12405
* @date: 2020/3/25-22:29
*/
public class CashFeeType implements FeeTypeInterf {
@Override
public String feeType() {
return "Cash";
}
}
5.不同類型計費的實現類
SMS
import cn.yzstu.buldermodule.impl.feetype.SMSFeeType;
import cn.yzstu.buldermodule.interf.FeeInterf;
import cn.yzstu.buldermodule.interf.FeeTypeInterf;
/**
* 類描述
*
* @author: 12405
* @date: 2020/3/25-22:37
*/
public abstract class SMSFee implements FeeInterf {
@Override
public FeeTypeInterf feeType() {
return new SMSFeeType();
}
}
Cash
import cn.yzstu.buldermodule.impl.feetype.CashFeeType;
import cn.yzstu.buldermodule.interf.FeeInterf;
import cn.yzstu.buldermodule.interf.FeeTypeInterf;
/**
* 類描述
*
* @author: 12405
* @date: 2020/3/25-22:44
*/
public abstract class CashFee implements FeeInterf {
@Override
public FeeTypeInterf feeType() {
return new CashFeeType();
}
}
6.計費的詳細實體類
中國移動
import java.util.UUID;
/**
* 類描述
*
* @author: 12405
* @date: 2020/3/25-22:49
*/
public class ChinaMobileFee extends SMSFee {
@Override
public String orderNo() {
return "MOBL"+ UUID.randomUUID();
}
@Override
public float price() {
return 10.0f;
}
}
中國聯通
import java.util.UUID;
/**
* 類描述
*
* @author: 12405
* @date: 2020/3/25-22:52
*/
public class ChinaUnicomFee extends SMSFee{
@Override
public String orderNo() {
return "UNC"+ UUID.randomUUID();
}
@Override
public float price() {
return 20.0f;
}
}
印尼TSEl
import java.util.UUID;
/**
* 類描述
*
* @author: 12405
* @date: 2020/3/25-22:56
*/
public class IndoTselFee extends SMSFee {
@Override
public String orderNo() {
return "TSEL"+ UUID.randomUUID();
}
@Override
public float price() {
return 2000.0f;
}
}
印尼ISAT
import java.util.UUID;
/**
* 類描述
*
* @author: 12405
* @date: 2020/3/25-22:57
*/
public class IndoIsatFee extends SMSFee {
@Override
public String orderNo() {
return "ISAT"+ UUID.randomUUID();
}
@Override
public float price() {
return 1000.0f;
}
}
招商銀行
import java.util.UUID;
/**
* 類描述
*
* @author: 12405
* @date: 2020/3/25-22:58
*/
public class CMBFee extends CashFee {
@Override
public String orderNo() {
return "CMB"+ UUID.randomUUID();
}
@Override
public float price() {
return 5.0f;
}
}
農業銀行
/**
* 類描述
*
* @author: 12405
* @date: 2020/3/25-23:01
*/
public class ABCFee extends CashFee {
@Override
public String orderNo() {
return "ABC"+ UUID.randomUUID();
}
@Override
public float price() {
return 2.0f;
}
}
Visa
import java.util.UUID;
/**
* 類描述
*
* @author: 12405
* @date: 2020/3/25-23:02
*/
public class VisaFee extends CashFee {
@Override
public String orderNo() {
return "V"+ UUID.randomUUID();
}
@Override
public float price() {
return 10.0f;
}
}
7.FeeConfig類(用於構建計費相關信息)
import cn.yzstu.bulidermodule.interf.FeeInterf;
import java.util.ArrayList;
import java.util.List;
/**
* 類描述
*
* @author: 12405
* @date: 2020/3/25-23:09
*/
public class FeeConfig {
private List<FeeInterf> feeList = new ArrayList<>();
//往當前訂單中加入可選的支付方式
public void addFee(FeeInterf feeInterf){
feeList.add(feeInterf);
}
//展示所有可選支付方式的相關信息
public void showMyFee(){
for (FeeInterf fee : feeList){
System.out.println("OrderNo:"+fee.orderNo());
System.out.println("FeeType:"+fee.feeType().feeType());
System.out.println("Money:"+fee.price());
}
}
}
8.FeeBuilder類(提供給國內外的不同客戶計費集)
import cn.yzstu.bulidermodule.impl.fee.*;
/**
* 類描述
*
* @author: 12405
* @date: 2020/3/25-23:23
*/
public class FeeBuilder {
//國內用戶的支付方式
public FeeConfig prepareChinaFee(){
FeeConfig feeConfig = new FeeConfig();
feeConfig.addFee(new ChinaMobileFee());
feeConfig.addFee(new ChinaUnicomFee());
feeConfig.addFee(new ABCFee());
feeConfig.addFee(new CMBFee());
return feeConfig;
}
//國外用戶的支付方式
public FeeConfig prepareIndoFee(){
FeeConfig feeConfig = new FeeConfig();
feeConfig.addFee(new IndoIsatFee());
feeConfig.addFee(new IndoTselFee());
feeConfig.addFee(new VisaFee());
return feeConfig;
}
}
9.FeeDemo測試(展示國內用戶獲取的計費集)
/**
* 類描述
*
* @author: 12405
* @date: 2020/3/25-23:30
*/
public class FeeDemo {
public static void main(String[] args) {
//獲取國內計費集
FeeConfig cFeeConfig = FeeBuilder.prepareChinaFee();
//獲取國外計費集
FeeConfig iFeeConfig = FeeBuilder.prepareIndoFee();
//展示國內用戶能夠獲取到的計費集
cFeeConfig.showMyFee();
}
}
"C:\Program Files\Java\jdk1.8.0_171\bin\java.exe" "-javaagent:E:\tools\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=54341:E:\tools\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_171\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\rt.jar;E:\Workspaces\IdeaProjects\DemoTest\out\production\DemoTest" cn.yzstu.bulidermodule.FeeDemo
OrderNo:MOBL3a989c63-ce7f-4210-8193-adcab306929f
FeeType:SMS
Money:10.0
OrderNo:UNCd3504a9d-62a5-4fde-91a1-49e1d1df2b23
FeeType:SMS
Money:20.0
OrderNo:ABC33369090-2639-4653-82fa-f76fb397fa24
FeeType:Cash
Money:2.0
OrderNo:CMB845f2043-e297-49fd-b397-a061be5adf64
FeeType:Cash
Money:5.0
Process finished with exit code 0
10.組件變動
上面我們已經用Builder成功獲取到了我們想要的國內用戶的計費方式集,其中FeeType是組件中不常改動的地方,而計費私有的屬性則是我們經常改動的地方,比如我們現在想改動中國移動的計費點,直接在ChinaMobileFee中改動價格即可。
import java.util.UUID;
/**
* 類描述
*
* @author: 12405
* @date: 2020/3/25-22:49
*/
public class ChinaMobileFee extends SMSFee {
@Override
public String orderNo() {
return "MOBL"+ UUID.randomUUID();
}
@Override
public float price() {
return 20.0f;//改動價格
}
}
"C:\Program Files\Java\jdk1.8.0_171\bin\java.exe" "-javaagent:E:\tools\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=54431:E:\tools\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_171\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\rt.jar;E:\Workspaces\IdeaProjects\DemoTest\out\production\DemoTest" cn.yzstu.bulidermodule.FeeDemo
OrderNo:MOBLd3140a28-55a3-4cb4-8de8-ce32043a3833
FeeType:SMS
Money:20.0
OrderNo:UNCb562defd-287b-4957-9a2c-e12a782a616b
FeeType:SMS
Money:20.0
OrderNo:ABCc6b54887-f18a-4e8a-b060-7a3fe6015a07
FeeType:Cash
Money:2.0
OrderNo:CMB21663c63-9a66-4b99-9ade-d5d9659975d3
FeeType:Cash
Money:5.0
Process finished with exit code 0
五、總結
該模式的主要優點如下:
- 各個具體的建造者相互獨立,有利於系統的擴展。
- 客戶端不必知道產品內部組成的細節,便於控制細節風險。
其缺點如下:
-
產品的組成部分必須相同,這限制了其使用範圍。
-
如果產品的內部變化複雜,該模式會增加很多的建造者類。
建造者(Builder)模式和工廠模式的關注點不同:建造者模式注重零部件的組裝過程,而工廠方法模式更注重零部件的創建過程,但兩者可以結合使用。