生成器模式(Builder)

本文详细介绍了生成器模式的概念、工作原理以及在软件开发中的实际应用案例。通过学习,读者将能够掌握如何利用生成器模式来创建复杂对象,同时避免使用大段的初始化代码,提高代码的可读性和可维护性。
摘要由CSDN通过智能技术生成
@@@模式定义:
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。


@@@练习示例: 
继续工厂方法模式中的导出数据的应用框架。


@@@示例代码:
\export\ExportHeaderModel.java

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

package export;

/**
 * 描述输出到文件头的内容的类
 */
public class ExportHeaderModel {
    /**
     * 分公司或门市点编号
     */
	private String depId;
	
	/**
	 * 导出数据的日期
	 */
	private String exportDate;

	public String getDepId() {
		return depId;
	}

	public void setDepId(String depId) {
		this.depId = depId;
	}

	public String getExportDate() {
		return exportDate;
	}

	public void setExportDate(String exportDate) {
		this.exportDate = exportDate;
	}
}

\export\ExportDataModel.java

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

package export;

/**
 * 描述输出数据的类
 */
public class ExportDataModel {
    /**
     * 产品编号
     */
	private String productId;
	
	/**
	 * 销售价格
	 */
	private double price;
	
	/**
	 * 销售数量
	 */
	private double amount;

	public String getProductId() {
		return productId;
	}

	public void setProductId(String productId) {
		this.productId = productId;
	}

	public double getPrice() {
		return price;
	}

	public void setPrice(double price) {
		this.price = price;
	}

	public double getAmount() {
		return amount;
	}

	public void setAmount(double amount) {
		this.amount = amount;
	}
}

\export\ExportFooterModel.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

package export;

/**
 * 描述输出到文件尾的内容的类
 */
public class ExportFooterModel {
    /**
     * 输出人
     */
	private String exportUser;

	public String getExportUser() {
		return exportUser;
	}

	public void setExportUser(String exportUser) {
		this.exportUser = exportUser;
	}
}

\export\ExportToTxt.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

package export;

import java.util.Collection;
import java.util.Map;

/**
 * 导出数据到文本文件的类
 */
public class ExportToTxt {
    /**
     * 导出数据到文本文件
     * @param ehm 文件头的内容
     * @param mapData 数据的内容
     * @param efm 文件尾的内容
     */
	public void export(ExportHeaderModel ehm,
			           Map<String, Collection<ExportDataModel>> mapData,
			           ExportFooterModel efm) {
		// 用来记录最终输出的文件内容
		StringBuffer buffer = new StringBuffer();
		// 1: 先来拼接文件头的内容
	    buffer.append(ehm.getDepId() + ", " + ehm.getExportDate() + "\n");
	    // 2: 接着来拼接文件体的内容
	    for (String tblName : mapData.keySet()) {
	    	// 先拼接表名称
	    	buffer.append(tblName + "\n");
	    	// 然后循环拼接具体数据
	    	for (ExportDataModel edm : mapData.get(tblName)) {
	    		buffer.append(edm.getProductId() + ", " + 
	    				edm.getPrice() + ", " + edm.getAmount() + "\n");
	    	}
	    }
	    // 3: 最后来拼接文件尾的内容
	    buffer.append(efm.getExportUser());
	    
	    // 为了演示的简洁性,省略写输出文件的代码
	    // 把要输出的内容输出到控制台看看
	    System.out.println("输出到文本文件的内容: \n" + buffer);
	}
}

\export\ExportToXml.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

package export;

import java.util.Collection;
import java.util.Map;

/**
 * 导出数据到XML文件的类
 */
public class ExportToXml {
	/**
     * 导出数据到XML文件
     * @param ehm 文件头的内容
     * @param mapData 数据的内容
     * @param efm 文件尾的内容
     */
	public void export(ExportHeaderModel ehm,
			           Map<String, Collection<ExportDataModel>> mapData,
			           ExportFooterModel efm) {
		// 用来记录最终输出的文件内容
		StringBuffer buffer = new StringBuffer();
		// 1: 先来拼接文件头的内容
		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");
	    // 2: 接着来拼接文件体的内容
	    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");
	    // 3: 最后来拼接文件尾的内容
	    buffer.append("  <Footer>\n");
	    buffer.append("    <ExportUser>" + efm.getExportUser() + "</ExportUser>\n");
	    buffer.append("  </Footer>\n");
	    buffer.append("</Report>\n");
	    
	    // 为了演示的简洁性,省略写输出文件的代码
	    // 把要输出的内容输出到控制台看看
	    System.out.println("输出到XML文件的内容: \n" + buffer);
	}
}

\user\Client.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

package user;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import export.ExportDataModel;
import export.ExportFooterModel;
import export.ExportHeaderModel;
import export.ExportToTxt;
import export.ExportToXml;

public class Client {
    public static void main(String[] args) {
    	// 准备测试数据
    	ExportHeaderModel ehm = new ExportHeaderModel();
    	ehm.setDepId("一分公司");
    	ehm.setExportDate("2013-06-02");
    	
    	Map<String, Collection<ExportDataModel>> mapData = 
    		new HashMap<String, Collection<ExportDataModel>>();
    	Collection<ExportDataModel> col = new ArrayList<ExportDataModel>();
    	
        ExportDataModel edm1 = new ExportDataModel();
        edm1.setProductId("产品001号");
        edm1.setPrice(100);
        edm1.setAmount(80);
        
        ExportDataModel edm2 = new ExportDataModel();
        edm2.setProductId("产品002号");
        edm2.setPrice(108);
        edm2.setAmount(56);
        
        // 把数据组装起来
        col.add(edm1);
        col.add(edm2);
        mapData.put("销售记录表", col);
        
        ExportFooterModel efm = new ExportFooterModel();
        efm.setExportUser("李小二");
        
        // 测试输出到文本文件
        ExportToTxt toTxt = new ExportToTxt();
        toTxt.export(ehm, mapData, efm);
        
        // 测试输出到xml文件
        ExportToXml toXml = new ExportToXml();
        toXml.export(ehm, mapData, efm);
    }
}

-------------------------------------------------------------
不使用模式时存在的问题 : 
对于不同的输出格式,处理步骤是一样的,但是每步的具体实现是不一样的。
构建每种输出格式的文件内容时,都会重复这几个处理步骤,应该提炼出来,形成公共的处理过程。
今后可能会有很多不同输出格式的要求,这就需要在处理过程不变的情况下,能方便地切换不同的输出格式的处理。
构建每种格式的数据文件的处理过程,应该和具体的步骤实现分开,
这样就能够复用处理过程,而且能很容易地切换不同的输出格式。
-------------------------------------------------------------


\export\Builder.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

package export;

import java.util.Collection;
import java.util.Map;

/**
 * 生成器接口,定义创建一个输出文件对象所需的各个部件的操作
 */
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);
}

\export\TxtBuilder.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

package export;

import java.util.Collection;
import java.util.Map;

/**
 * 实现导出数据到文本文件的具体生成器类
 */
public class TxtBuilder implements Builder {
	/**
	 * 用来记录构建的文件的内容,相当于产品
	 */
	private StringBuffer buffer = new StringBuffer();
	
	@Override
	public void buildHeader(ExportHeaderModel ehm) {
		 buffer.append(ehm.getDepId() + ", " + ehm.getExportDate() + "\n");
	}
	
	@Override
	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;
	}
}

\export\XmlBuilder.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

package export;

import java.util.Collection;
import java.util.Map;

/**
 * 实现导出数据到XML文件的具体生成器类
 */
public class XmlBuilder implements Builder {
	/**
	 * 用来记录构建的文件的内容,相当于产品
	 */
	private StringBuffer buffer = new StringBuffer();
	
	@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");
	}

	public StringBuffer getResult() {
		return buffer;
	}
}

\export\Director.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

package export;

import java.util.Collection;
import java.util.Map;

/**
 * 指导者,指导使用生成器的接口来构建输出的文件的对象
 */
public class Director {
    /**
     * 持有当前需要使用的生成器对象
     */
	private Builder builder;
	
	/**
	 * 构造方法,传入生成器对象
	 * @param 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) {
		// 1: 先构建Header
	    builder.buildHeader(ehm);
	    // 2: 然后构建Body
	    builder.buildBody(mapData);
	    // 3: 再构建Footer
	    builder.buildFooter(efm);
	}
}

\user\Client2.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

package user;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import export.Director;
import export.ExportDataModel;
import export.ExportFooterModel;
import export.ExportHeaderModel;
import export.TxtBuilder;
import export.XmlBuilder;

public class Client2 {
    public static void main(String[] args) {
    	// 准备测试数据
    	ExportHeaderModel ehm = new ExportHeaderModel();
    	ehm.setDepId("一分公司");
    	ehm.setExportDate("2013-06-02");
    	
    	Map<String, Collection<ExportDataModel>> mapData = 
    		new HashMap<String, Collection<ExportDataModel>>();
    	Collection<ExportDataModel> col = new ArrayList<ExportDataModel>();
    	
        ExportDataModel edm1 = new ExportDataModel();
        edm1.setProductId("产品001号");
        edm1.setPrice(100);
        edm1.setAmount(80);
        
        ExportDataModel edm2 = new ExportDataModel();
        edm2.setProductId("产品002号");
        edm2.setPrice(108);
        edm2.setAmount(56);
        
        // 把数据组装起来
        col.add(edm1);
        col.add(edm2);
        mapData.put("销售记录表", col);
        
        ExportFooterModel efm = new ExportFooterModel();
        efm.setExportUser("李小二");
        
        // 测试输出到文本文件
        TxtBuilder txtBuilder = new TxtBuilder();
        // 创建指导者对象
        Director txtDirector = new Director(txtBuilder);
        txtDirector.construct(ehm, mapData, efm);
        // 把要输出的内容输出到控制台看看
        System.out.println("输出到文本文件的内容: \n" +
        		txtBuilder.getResult());
        
        // 测试输出到xml文件
        XmlBuilder xmlBuilder = new XmlBuilder();
        // 创建指导者对象
        Director xmlDirector = new Director(xmlBuilder);
        xmlDirector.construct(ehm, mapData, efm);
        // 把要输出的内容输出到控制台看看
        System.out.println("输出到XML文件的内容: \n" +
        		xmlBuilder.getResult());
        
    }
}

@@@模式的实现:
1. 生成器中的每个方法可以有两部分的功能,一部分是创建部件对象,另一部分是组装部件。
2. 指导者承担的是整体构建算法部分,是相对不变的。
3. 产品构建过程中,指导者和生成器之间可能会存在比较复杂的交互过程。
4. 客户端最终从Builder实现里面获取最终装配好的产品。
5. 一般不需要对产品定义抽象接口,因为最终构建出来的产品千差万别。


@@@模式的功能:
生成器模式的主要功能是构建复杂的产品,而且是细化的、分步骤地构建产品,
也就是生成器模式重在一步一步解决构造复杂对象的问题。
更重要的是,这个构建的过程是统一的、固定不变的,变化的部分放到生成器部分了,只要配置不同的生成器,
那么同样的构建过程,就能构建出不同的产品来。


@@@模式的构成:
1. Builder接口,定义了如何构建各个部件,如何装配产品。
2. Director,定义了使用部件装配产品的步骤。


@@@模式的优点:
1. 松散耦合。
2. 可以很容易地改变产品的内部表示。
3. 更好的复用性


@@@模式的缺点:



@@@模式的本质:
分离整体构建算法和部件构造过程。


@@@模式体现的设计原则:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值