builder 模式的重心在于分離建構算法和具體的構造實作,進而使建構算法可以重用。
builder 模式的構成分為兩部分:一部分是builder接口,定義了如何建構各個部件,并裝配到産品中去;另一部分是director,定義如何來建構産品,director 負責整體的建構算法,而且通常是分步來執行的。
注:這裡的建構算法是指:通過什麼樣的方式來組裝産品;建構産品指的是:建構一個複雜對象。
builder 模式就是将建構産品部件群組裝産品的過程分開,即實作了産品部件群組裝産品過程的解耦,可以使得組裝産品過程得到複用
public class exportheadermodel {
private string depid;
private string exportdate;
省略getter 和 setter
}
public class exportdatamodel {
private string productid;
private double price;
private double amount;
省略getter 和 setter
}
public class exportfootermodel {
private string exportuser;
省略getter 和 setter
}
/**
* 生成器接口,定義一個輸出檔案對象所需的各個部件的操作
*
*/
public interface builder {
/**
* 建構輸出檔案的header部分
* @param ehm 檔案頭的内容
*/
public void buildheader(exportheadermodel ehm);
/**
* 建構輸出檔案的body部分
* @param mapdata 要輸出檔案的資料内容
*/
public void buildbody(map<string, collection<exportdatamodel>> mapdata);
/**
* 建構要輸出檔案的footer部分
* @param efm 檔案尾的内容
*/
public void buildfooter(exportfootermodel efm);
* 實作導出資料到文本檔案的生成器
public class txtbuilder implements builder {
/**
* 用來記錄建構檔案的内容,相當于産品
private stringbuffer buffer = new stringbuffer();
@override
public void buildheader(exportheadermodel ehm) {
buffer.append(ehm.getdepid() + "," + ehm.getexportdate() + "\n");
}
public void buildbody(map<string, collection<exportdatamodel>> mapdata) {
for(string tblname : mapdata.keyset()){
buffer.append(tblname + "\n");
for(exportdatamodel edm : mapdata.get(tblname)){
buffer.append(edm.getproductid() + "," + edm.getprice() + "," + edm.getamount() + "\n");
}
}
}
@override
public void buildfooter(exportfootermodel efm) {
buffer.append(efm.getexportuser());
}
public stringbuffer getresult(){
return buffer;
public class xmlbuilder implements builder {
@override
public void buildheader(exportheadermodel ehm) {
buffer.append("<?xml version='1.0' encoding='gb2312' ?>\n");
buffer.append("<report>\n");
buffer.append(" <header>\n");
buffer.append(" <depid>" + ehm.getdepid() + "</depid>\n");
buffer.append(" <exportdate>" + ehm.getexportdate() + "</exportdate>\n");
buffer.append(" </header>\n");
@override
public void buildbody(map<string, collection<exportdatamodel>> mapdata) {
buffer.append(" <body>\n");
for(string tblname : mapdata.keyset()){
buffer.append(" <datas tablename=\"" + tblname + "\">\n");
for(exportdatamodel edm : mapdata.get(tblname)){
buffer.append(" <data>\n");
buffer.append(" <productid>" + edm.getproductid() + "</productid>\n");
buffer.append(" <price>" + edm.getprice() + "</price>\n");
buffer.append(" <amount>" + edm.getamount() + "</amount>\n");
buffer.append(" </data>\n");
}
buffer.append(" </datas>\n");
}
buffer.append(" </body>\n");
}
@override
public void buildfooter(exportfootermodel efm) {
buffer.append(" <footer>\n");
buffer.append(" <exportuser>" + efm.getexportuser() + "</exportuser>\n");
buffer.append(" </footer>\n");
buffer.append("</report>\n");
return buffer;
* 指導者,指導使用生成器的接口來建構輸出的檔案對象
public class director {
* 持有目前需要使用的生成器對象
private builder builder;
public director(builder builder){
this.builder = builder;
}
/**
* 指導生成器建構最終的輸出檔案的對象
* @param ehm 檔案頭的内容
* @param mapdata 資料的内容
* @param efm 檔案尾的内容
public void construct(exportheadermodel ehm, map<string, collection<exportdatamodel>> mapdata,
exportfootermodel efm){
//建構header
builder.buildheader(ehm);
//建構body
builder.buildbody(mapdata);
//建構footer
builder.buildfooter(efm);
}
public class client {
public static void main(string[] args) {
exportheadermodel ehm = new exportheadermodel();
ehm.setdepid("一分公司");
ehm.setexportdate("2011-06-12");
map<string, collection<exportdatamodel>> mapdata = new hashmap<string, collection<exportdatamodel>>();
collection<exportdatamodel> coll = new arraylist<exportdatamodel>();
exportdatamodel edml = new exportdatamodel();
edml.setamount(80);
edml.setproductid("産品001号");
edml.setprice(100);
coll.add(edml);
exportdatamodel edm2 = new exportdatamodel();
edm2.setamount(60);
edm2.setproductid("産品002号");
edm2.setprice(120);
coll.add(edm2);
mapdata.put("銷售記錄表", coll);
exportfootermodel efm = new exportfootermodel();
efm.setexportuser("張三");
txtbuilder txtbuilder = new txtbuilder();
director director = new director(txtbuilder);
director.construct(ehm, mapdata, efm);
system.out.println("輸出到文本檔案的内容:\n" + txtbuilder.getresult());
xmlbuilder xmlbuilder = new xmlbuilder();
director director2 = new director(xmlbuilder);
director2.construct(ehm, mapdata, efm);
system.out.println("輸出到xml檔案的内容:\n" + xmlbuilder.getresult());
● 使用生成器模式建立複雜對象:
① 由于使用builder 模式來建立某個對象,是以就沒有必要再定義一個builder接口,直接提供一個具體的建構器類就可以了。
② 對于建立一個複雜的對象,可能會有很多種不同的選擇和步驟,幹脆去掉“director”,把director的功能和client 的功能合并起來,也就是說這個時候,client 相當于指導者,它來指導建構器類去建構需要的複雜對象。
public class concretebuilder {
private string contractid;
private string personname;
private string companyname;
private long begindate;
private long enddate;
private string otherdata;
/**
* 構造方法 傳入必填資料
* @param contractid 保險合同号
* @param begindate 保險開始生效的日期
* @param enddate 保險失效的日期
public concretebuilder(string contractid, long begindate, long enddate){
this.contractid = contractid;
this.begindate = begindate;
this.enddate = enddate;
* 選填資料,被保險人
* @param personname 被保險人名
* @return 建構對象
*/
public concretebuilder setpersonname(string personname){
this.personname = personname;
return this;
* 選填資料,被保險公司
* @param companyname 被保險公司名
* @return 建構對象
public concretebuilder setcompanyname(string companyname){
this.companyname = companyname;
return this;
}
* 選填資料,其它資料
* @param otherdata 其它資料
* @return 建構對象
public concretebuilder setotherdata(string otherdata){
this.otherdata = otherdata;
return this;
public insurancecontract build(){
if(contractid == null || contractid.trim().length() == 0){
throw new illegalargumentexception("合同編号不能空!");
}
boolean signperson = (personname != null && personname.trim().length() > 0);
boolean signcompany = (companyname != null && companyname.trim().length() > 0);
if(!(signperson ^ signcompany)){
throw new illegalargumentexception("一份保險不能沒有簽訂對象,且不能同時與人和公司簽訂!");
if(begindate <= 0){
throw new illegalargumentexception("合同必須有保險開始生效的日期!");
if(enddate <= 0){
throw new illegalargumentexception("合同必須有保險失效的日期!");
}
if(enddate <= begindate){
throw new illegalargumentexception("保險失效日期必須大于生效日期!");
return new insurancecontract(this);
public string getcontractid() {
return contractid;
}
public string getpersonname() {
return personname;
}
public string getcompanyname() {
return companyname;
public long getbegindate() {
return begindate;
public long getenddate() {
return enddate;
public string getotherdata() {
return otherdata;
* 保險合同對象
* @author joe
public class insurancecontract {
* 保險合同編号
private string constractid;
* 被保險的人
*/
private string personname;
* 被保險的公司
*/
private string companyname;
/**
* 保險開始生效的日期
*/
private long begindate;
/**
* 保險失效的日期
*/
private long enddate;
* 其它資料
private string otherdata;
* 構造方法,通路級别是同包能通路
* @param builder
insurancecontract(concretebuilder builder){
this.constractid = builder.getcontractid();
this.personname = builder.getpersonname();
this.companyname = builder.getcompanyname();
this.begindate = builder.getbegindate();
this.enddate = builder.getenddate();
this.otherdata = builder.getotherdata();
}
public void someoperation(){
system.out.println("now in insurance contract someoperation == " + this.constractid);
}
concretebuilder builder = new concretebuilder("001", 82345l, 67890l);
insurancecontract contract = builder.setpersonname("張三").setotherdata("test").build();
contract.someoperation();
====================================分割線================================
最新内容請見作者的github頁:http://qaseven.github.io/