转载自:http://blog.csdn.net/top_code/article/details/8469297
定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
类型:对象创建型模式
类图:
- Builder:生成器接口,定义创建一个Product对象所需要的各个部件的操作。
- ConcreteBuilder:具体的生成器实现,实现各个部件的创建,并负责组装Product对象的各个部件,同时还提供一个让用户获取组装完成后的产品对象的方法。
- Director:指导者,也被称导向者,主要用来使用Builder接口,以一个统一的过程来构建所需要的Product对象。
- Product:产品,表示被生成器构建的复杂对象,包含多个部件。
生成器模式示例代码
1、生成器接口定义的示例代码
- /**
- * 生成器接口,定义创建一个产品对象所需的各个部件的操作
- * @author FX_SKY
- *
- */
- public interface Builder {
- /**
- * 示意方法,构建某个部件
- */
- public void buildPart();
- }
2、具体生成器实现的示例代码
- /**
- * 具体的生成器实现对象
- * @author FX_SKY
- *
- */
- public class ConcreteBuilder implements Builder {
- private Product resultProduct;
- /**
- * 获取生成器最终构建的产品对象
- * @return
- */
- public Product getResultProduct() {
- return resultProduct;
- }
- @Override
- public void buildPart() {
- //构建某个部件的功能处理
- }
- }
3、相应的产品对象接口的示例代码
- /**
- * 被构建的产品对象的接口
- * @author FX_SKY
- *
- */
- public interface Product {
- //定义产品的操作
- }
4、最后是指导者的实现示意,示例代码如下:
- /**
- * 指导者,指导使用生成器的接口来构建产品对象
- * @author FX_SKY
- *
- */
- public class Director {
- /**
- * 持有当前需要使用的生成器对象
- */
- private Builder builder;
- /**
- * 构造方法,传人生成器对象
- * @param builder
- */
- public Director(Builder builder) {
- this.builder = builder;
- }
- /**
- * 示意方法,指导生成器构建最终的产品对象
- */
- public void construct(){
- //通过使用生成器接口来构建最终的产品对象
- builder.buildPart();
- }
- }
应用场景-- 导出数据的应用框架
在讨论工厂方法模式的时候,提供了一个导出数据的应用框架。
对于导出数据的应用框架,通常在导出数据上,会有一些约束的方式,比如导出成文本格式、数据库备份形式、Excel格式、Xml格式等。
在工厂方法模式章节里面,讨论并使用工厂方法模式来解决了如何选择具体导出方式的问题,并没有涉及到每种方式具体如何实现。
换句话说,在讨论工厂方法模式的时候,并没有讨论如何实现导出成文本、Xml等具体格式,本章就来讨论这个问题。
对于导出数据的应用框架,通常对于具体的导出内容和格式是有要求的,加入现在有如下要求,简单描述一下:
- 导出的文件,不管是什么格式,都分成3个部分,分别是文件头、文件体、文件尾。
- 在文件头部分,需要描述如下信息:分公司或者门市编号、导出数据的日期。
- 在文件体部分,需要描述如下信息:表名称,然后分条描述数据。
- 在文件尾部分,需要描述如下信息:输出人。
1、下面将描述文件各个部分的数据对象定义出来
描述输出到文件头的内容的对象,示例代码如下:
- /**
- * 描述输出到文件头的内容的对象
- * @author FX_SKY
- *
- */
- 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;
- }
- }
描述输出数据的对象,示例代码如下:
- /**
- * 描述输出数据的对象
- * @author FX_SKY
- *
- */
- 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;
- }
- }
描述输出到文件尾的内容的对象,示例代码如下:
- /**
- * 描述输出到文件尾的内容的对象
- * @author FX_SKY
- *
- */
- public class ExportFooterModel {
- /**
- * 输出人
- */
- private String exportUser;
- public String getExportUser() {
- return exportUser;
- }
- public void setExportUser(String exportUser) {
- this.exportUser = exportUser;
- }
- }
2、定义Builder接口,主要是把导出各种格式文件的处理过程的步骤定义出来,每个步骤负责构建最终导出文件的一部分。示例代码如下:
- /**
- * 生成器接口,定义创建一个输出文件对象所需的各个部件的操作
- * @author FX_SKY
- *
- */
- public interface Builder {
- /**
- * 构建输出文件的Header部分
- * @param ehm
- */
- public void buildHeader(ExportHeaderModel ehm);
- /**
- * 构建输出文件的Body部分
- * @param mapData
- */
- public void buildBody(Map<String,List<ExportDataModel>> mapData);
- /**
- * 构建输出文件的Footer部分
- * @param efm
- */
- public void buildFooter(ExportFooterModel efm);
- }
3、具体的生成器实现。
导出到文本文件的的生成器实现。示例代码如下:
- /**
- * 实现导出文件到文本文件的生成器对象
- * @author FX_SKY
- *
- */
- 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, List<ExportDataModel>> mapData) {
- for(String tablName : mapData.keySet()){
- //先拼接表名
- buffer.append(tablName+"\n");
- //然后循环拼接具体数据
- for(ExportDataModel edm : mapData.get(tablName)){
- buffer.append(edm.getProductId()+","+edm.getPrice()+","+edm.getAmount()+"\n");
- }
- }
- }
- @Override
- public void buildFooter(ExportFooterModel efm) {
- buffer.append(efm.getExportUser());
- }
- public StringBuffer getResult(){
- return buffer;
- }
- }
导出到Xml文件的的生成器实现。示例代码如下:
- /**
- * 实现导出文件到Xml文件的生成器对象
- * @author FX_SKY
- *
- */
- public class XmlBuilder implements Builder {
- /**
- * 用来记录构建的文件的内容,相当于产品
- */
- private StringBuffer buffer = new StringBuffer();
- @Override
- public void buildHeader(ExportHeaderModel ehm) {
- buffer.append("<?xml version='1.0' encoding='UTF-8'?>\n");
- buffer.append("<Report>\n");
- buffer.append("\t<Header>\n");
- buffer.append("\t\t<DepId>"+ehm.getDepId()+"</DepId>\n");
- buffer.append("\t\t<ExportDate>"+ehm.getExportDate()+"</ExportDate>\n");
- buffer.append("\t</Header>\n");
- }
- @Override
- public void buildBody(Map<String, List<ExportDataModel>> mapData) {
- buffer.append("\t<Body>\n");
- for(String tablName : mapData.keySet()){
- //先拼接表名
- buffer.append("\t\t<Datas TableName=\""+tablName+"\">\n");
- //然后循环拼接具体数据
- for(ExportDataModel edm : mapData.get(tablName)){
- buffer.append("\t\t\t<Data>\n");
- buffer.append("\t\t\t\t<ProductId>"+edm.getProductId()+"</ProductId>\n");
- buffer.append("\t\t\t\t<Price>"+edm.getPrice()+"</Price>\n");
- buffer.append("\t\t\t\t<Amount>"+edm.getAmount()+"</Amount>\n");
- buffer.append("\t\t\t</Data>\n");
- }
- buffer.append("\t\t</Datas>\n");
- }
- buffer.append("\t</Body>\n");
- }
- @Override
- public void buildFooter(ExportFooterModel efm) {
- buffer.append("\t<Footer>\n");
- buffer.append("\t\t<ExportUser>"+efm.getExportUser()+"</ExportUser>\n");
- buffer.append("\t</Footer>\n");
- buffer.append("</Report>\n");
- }
- public StringBuffer getResult(){
- return buffer;
- }
- }
4、指导者。有了具体的生成器实现后,需要由指导者来指导它进行具体的产品构建。示例代码如下:
- /**
- * 指导者,指导使用生成器的接口来构建输出的文件对象
- *
- * @author FX_SKY
- *
- */
- public class Director {
- /**
- * 持有当前需要的使用的生成器对象
- */
- private Builder builder;
- /**
- * 构造方法,传入生成器对象
- *
- * @param builder
- */
- public Director(Builder builder) {
- this.builder = builder;
- }
- public void construct(ExportHeaderModel ehm,
- Map<String, List<ExportDataModel>> mapData, ExportFooterModel efm) {
- //1.先构建Header
- builder.buildHeader(ehm);
- //2.然后构建Body
- builder.buildBody(mapData);
- //3.再构建Footer
- builder.buildFooter(efm);
- }
- }
5、客户端测试代码如下:
- public class Client {
- /**
- * @param args
- */
- public static void main(String[] args) {
- //准备测试数据
- ExportHeaderModel ehm = new ExportHeaderModel();
- ehm.setDepId("一分公司");
- ehm.setExportDate("2010-05-18");
- Map<String, List<ExportDataModel>> mapData = new HashMap<String, List<ExportDataModel>>();
- List<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(120);
- edm2.setAmount(280);
- ExportDataModel edm3 = new ExportDataModel();
- edm3.setProductId("产品003号");
- edm3.setPrice(320);
- edm3.setAmount(380);
- col.add(edm1);
- col.add(edm2);
- col.add(edm3);
- mapData.put("销售记录表", col);
- ExportFooterModel efm = new ExportFooterModel();
- efm.setExportUser("张三");
- //测试输出到文本文件
- TxtBuilder txtBuilder = new TxtBuilder();
- //创建指导者对象
- Director director = new Director(txtBuilder);
- director.construct(ehm, mapData, efm);
- //把要输出的内容输出到控制台看看
- System.out.println("输出到文本文件的内容:"+txtBuilder.getResult().toString());
- XmlBuilder xmlBuilder = new XmlBuilder();
- Director director2 = new Director(xmlBuilder);
- director2.construct(ehm, mapData, efm);
- //把要输出的内容输出到控制台看看
- System.out.println("输出到Xml文件的内容:"+xmlBuilder.getResult().toString());
- }
- }
生成器模式的功能
生成器模式的主要功能是构建复杂的产品,而且是细化的,分步骤的构建产品,也就是生成器模式重在一步一步解决构造复杂对象的问题。如果仅仅这么认知生成器模式的功能是不够的。
更为重要的是,这个构建的过程是统一的、固定不变的,变化的部分放到生成器部分了,只要配置不同的生成器,那么同样的构建过程,就能构建出不同的产品来。
使用生成器模式构建复杂的对象
考虑这样的一个实际应用,Android图片异步加载框架,需要要创建图片加载配置的对象,里面很多属性的值都有约束,要求创建出来的对象是满足这些约束规则的。约束规则比如,线程池的数量不能小于2个、内存图片缓存的大小不能为负值等等。
要想简洁直观、安全性好,有具有很好的扩展性地创建这个对象的话,一个较好的选择就是使用Builder模式,把复杂的创建过程通过Builder来实现。
采用Builder模式来构建复杂的对象,通常会对Builder模式进行一定的简化,因为目标明确,就是创建某个复杂对象,因此做适当简化会使程序更简洁。大致简化如下:
- 由于是用Builder模式来创建某个对象,因此就没有必要再定义一个Builder接口,直接提供一个具体的构建器类就可以了。
- 对于创建一个负责的对象,可能会有很多种不同的选择和步骤,干脆去掉“指导者”,把指导者的功能和Client的功能合并起来,也就是说,Client就相当于指导者,它来指导构建器类去构建需要的复杂对象。
- public final class ImageLoaderConfiguration {
- final Executor taskExecutor;
- final int memoryCacheSize;
- final int threadPoolSize;
- final int threadPriority;
- final boolean writeLogs;
- private ImageLoaderConfiguration(final Builder builder) {
- taskExecutor = builder.taskExecutor;
- threadPoolSize = builder.threadPoolSize;
- threadPriority = builder.threadPriority;
- memoryCacheSize = builder.memoryCacheSize;
- writeLogs = builder.writeLogs;
- }
- /**
- * Builder for {@link ImageLoaderConfiguration}
- *
- * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
- */
- public static class Builder {
- public static final int DEFAULT_THREAD_POOL_SIZE = 3;
- public static final int DEFAULT_THREAD_PRIORITY = Thread.NORM_PRIORITY - 1;
- private int memoryCacheSize = 0;
- private Executor taskExecutor = null;
- private int threadPoolSize = DEFAULT_THREAD_POOL_SIZE;
- private int threadPriority = DEFAULT_THREAD_PRIORITY;
- private boolean writeLogs = false;
- public Builder() {
- }
- public Builder taskExecutor(Executor executor) {
- if (threadPoolSize != DEFAULT_THREAD_POOL_SIZE || threadPriority != DEFAULT_THREAD_PRIORITY) {
- }
- this.taskExecutor = executor;
- return this;
- }
- public Builder threadPoolSize(int threadPoolSize) {
- this.threadPoolSize = threadPoolSize;
- return this;
- }
- public Builder threadPriority(int threadPriority) {
- if (threadPriority < Thread.MIN_PRIORITY) {
- this.threadPriority = Thread.MIN_PRIORITY;
- } else {
- if (threadPriority > Thread.MAX_PRIORITY) {
- this.threadPriority = Thread.MAX_PRIORITY;
- } else {
- this.threadPriority = threadPriority;
- }
- }
- return this;
- }
- public Builder memoryCacheSize(int memoryCacheSize) {
- if (memoryCacheSize <= 0) throw new IllegalArgumentException("memoryCacheSize must be a positive number");
- this.memoryCacheSize = memoryCacheSize;
- return this;
- }
- public Builder writeDebugLogs() {
- this.writeLogs = true;
- return this;
- }
- /** Builds configured {@link ImageLoaderConfiguration} object */
- public ImageLoaderConfiguration build() {
- initEmptyFieldsWithDefaultValues();
- return new ImageLoaderConfiguration(this);
- }
- private void initEmptyFieldsWithDefaultValues() {
- if (taskExecutor == null) {
- }
- }
- }
- }
客户端调用示例代码如下:
- public class Client {
- /**
- * @param args
- */
- public static void main(String[] args) {
- ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder()
- .taskExecutor(Executors.newCachedThreadPool())
- .threadPoolSize(3)
- .threadPriority(Thread.MIN_PRIORITY + 3)
- .memoryCacheSize(1024*16)
- .build();
- }
- }
生成器模式的优点
松散耦合
生成器模式可以用同一个构建算法构建出表现上完全不同的产品,实现产品构建和产品表现上的分离。生成器模式正是把产品构建的过程独立出来,使它和具体产品的表现分松散耦合,从而使得构建算法可以复用,而具体产品表现也可以很灵活地、方便地扩展和切换。
可以很容易的改变产品的内部表示
在生成器模式中,由于Builder对象只是提供接口给Director使用,那么具体部件创建和装配方式是被Builder接口隐藏了的,Director并不知道这些具体的实现细节。这样一来,要想改变产品的内部表示,只需要切换Builder接口的具体实现即可,不用管Director,因此变得很容易。
更好的复用性
生成器模式很好的实现构建算法和具体产品实现的分离。这样一来,使得构建产品的算法可以复用。同样的道理,具体产品的实现也可以复用,同一个产品的实现,可以配合不同的构建算法使用。
生成器模式的本质:分离整体构建算法和部件构造。
虽然在生成器模式的整体构建算法中,会一步一步引导Builder来构建对象,但这并不是说生成器主要就是用来实现分步骤构建对象的。生成器模式的重心还是在于分离整体构建算法和部件构造,而分步骤构建对象不过是整体构建算法的一个简单表现,或者说是一个附带产物。
何时选用生成器模式
建议在以下情况中选用生成器模式。
- 如果创建对象的算法,应该独立于该对象的组成部分以及它们的装配方式时。
- 如果同一个构建过程有着不同的表示时。
相关推荐
生成器模式(Builder Pattern)是一种设计模式,它允许我们分步骤构建复杂对象,而无需暴露其构造过程。这种模式在创建对象时提供了更大的灵活性,特别是当构造过程需要多个步骤或者对象有不同的构造方式时。Builder...
生成器模式(Builder Pattern)是Java设计模式中的创建型模式之一,主要解决复杂对象的构建问题,通过将构造过程逐步分解,使得构造过程与表示分离,使得同样的构建过程可以创建不同的表示。这种模式通常用于创建...
" JAVA 设计模式概述" JAVA 设计模式是指在软件设计过程中,为了提高代码的可维护性、灵活性和可扩展性所使用的一些惯用解决方案。JAVA 设计模式可以分为三种:创建模式、结构模式和行为模式。 1. 创建模式 创建...
在《Java设计模式》这本书的模拟试题及其参考答案中,涉及了多条设计模式的知识点,以及它们的应用场景和实现方法。现在将这些知识点详细地解释如下: 1. 开闭原则(Open-Closed Principle, OCP): 开闭原则是面向...
生成器模式(Builder Pattern)是一种创造型设计模式,它将一个复杂对象的构建与它的表示分离,使得同样的构建可以创建不同的表示。这种模式可以在以下情况下使用: 1. 当创建复杂对象的算法应该独立于该对象的组成...
FreeBuilder为 Java 1.6 自动生成 Builder 模式。当设计类的构造函数或静态工厂具有多个参数时,Builder 模式是一个不错的选择。—— Effective Java,第二版,第39页背景在 Java 中实现 Builder 模式容易出错和...
Java设计模式-建造者模式详解 Java设计模式-建造者模式详解将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。生成器模式(Builder)是使用多个“小型”工厂来最终创建出一个完整对象。...
### Java设计模式详解 #### 一、引言 自从J2EE(Java 2 Enterprise Edition)的出现,Java的企业级应用程序开发得到了极大的简化。然而,随着J2EE在各行各业中的广泛应用,开发人员逐渐意识到需要一种更为系统化的...
### Java设计模式与原理 #### 一、概述 在软件工程领域,设计模式是指在特定情境下解决软件设计问题的最佳实践。《Java 设计模式与原理》这本书被誉为Java程序员的必备指南之一,它深入浅出地讲解了23种经典的设计...
Java设计模式是软件开发中的重要概念,源自于“Gang of Four”(GoF)的经典著作《设计模式:可复用面向对象软件的基础》。这些模式代表了在编写可维护和扩展的Java应用时,经过时间和实践验证的最佳实践。张跃平和...
### JAVA设计模式详解 #### 一、引言:学习GOF设计模式的重要性 设计模式是在软件工程领域中解决常见问题的一系列解决方案。Gang of Four(GOF)的经典著作《设计模式:可复用面向对象软件的基础》为软件开发者...
生成器模式是一种设计模式,属于创建型模式,它允许我们分步骤构建复杂对象,而无需提前知道整个对象的完整结构。这种模式的核心在于延迟初始化,它使得我们可以根据需要逐步构建对象,而不是一次性创建所有部分。在...
Java设计模式是软件开发中的重要概念,它是一种在特定情境下解决常见问题的经验总结,能够提升代码的可读性、可维护性和复用性。本资料包“java设计模式源码和笔记(第一部分)”提供了对Java设计模式的深入理解和...
《JAVA设计模式》是一本深入探讨Java编程中设计模式的宝贵资源。设计模式是软件开发中的通用解决方案,它们是经过时间验证的、在特定场景下解决问题的最佳实践。这本书的.chm格式表明它可能是一个帮助文件或电子书,...
文件可能还包含了Builder模式与其他设计模式(如工厂模式、抽象工厂模式)的对比,以及如何在Java、C#等编程语言中使用Builder模式的示例代码。通过学习这个文件,可以深入理解Builder模式,并掌握如何在项目中有效...
### JAVA23中设计模式详解 #### 一、概述 设计模式是在软件设计过程中解决常见问题的一套可复用的解决方案。《JAVA23中设计模式》是一份针对Java程序员的指南,旨在通过一系列示例和理论讲解,帮助读者理解和掌握...
Java设计模式是一种针对软件开发中常见问题的典型解决方案,是面向对象编程的精髓所在。设计模式可以分为三种类型,即创建型模式、结构型模式和行为型模式,共包括23种经典的设计模式。本文所涉及的增强版设计模式...
### 高清Java设计模式(疯狂Java联盟版) #### 概述 《高清Java设计模式(疯狂Java联盟版)》是一份由李刚老师及其团队精心编写的关于Java设计模式的指南资料。这份资料旨在帮助Java开发者更好地理解和应用设计...
在Java中,设计模式尤其重要,因为它们可以帮助我们编写出更灵活、可维护和易于扩展的代码。以下是对给定文件中提到的几种设计模式的详细解释: 1. **简单工厂模式(Simple Factory)**: - 简单工厂模式是一种...
Java设计模式和架构图是软件开发中的重要概念,它们对于构建高效、可维护的系统至关重要。设计模式是解决常见编程问题的经验总结,而架构图则是系统结构的可视化表示,帮助我们理解和规划系统的整体布局。 首先,...