设计模式之美:Builder(生成器)
索引
意图
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
Separate the construction of a complex object from its representation so that the same construction process can create different representations.
结构

参与者
Builder
- 为创建一个 Product 对象的各个部件指定抽象接口。
ConcreteBuilder
- 实现 Builder 的接口以构造和装配该产品的各个部件。
- 定义并明确它所创建的表示。
- 提供一个检索产品的接口。
Director
- 构造一个使用 Builder 接口的对象。
Product
- 表示被构造的复杂对象。ConcreteBuilder 创建该产品的内部表示并定义它的装配过程。
- 包含定义组成部件的类,包括将这些部件装配成最终产品的接口。
适用性
在以下情况下可以使用 Builder 模式:
- 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。
- 当构造过程必须允许被构造的对象有不同的表示时。
效果
- 它使你可以改变一个产品的内部表示。在改变该产品的内部表示时所要做的只是定义一个新的 ConcreteBuilder。
- 它将构造代码和表示代码分开,提高了对象的模块性。客户不需要知道定义产品内部结构的类的所有信息。
- 它使你可以对构造过程进行更精细的控制。对象是在 Director 的控制下一步一步构造的,仅当产品构造完成时 Director 才从 Builder 中取回它。
相关模式
- Abstract Factory 和 Builder 相似,因为它也可以创建复杂对象。区别是 Builder 着重于一步步构造一个复杂对象。而 Abstract Factory 着重于多个系列的产品对象(或简单或复杂)。Builder 是在最后一步返回产品,Abstract Factory 是立即返回。
- Composite通常是用 Builder 生成的。
实现

实现方式(一):Builder 为每个构件定义一个操作。
通常有一个抽象的 Builder 类为 Director 可能要求创建的每一个 "构件" 定义一个操作。这些操作默认情况下什么都不做。一个 ConcreteBuilder 类对它感兴趣的 "构件" 对应的操作进行重定义。
namespace BuilderPattern.Implementation1
{
public class ComplexProduct
{
public string ValueDependOnWeather { get; set; }
public string ValueDependOnFortune { get; set; }
} public abstract class AbstractComplexProductBuilder
{
protected ComplexProduct _complexProduct; public void BeginBuild(ComplexProduct existingComplexProduct = null)
{
if (existingComplexProduct == null)
_complexProduct = new ComplexProduct();
else
_complexProduct = existingComplexProduct;
} public virtual void BuildValueDependOnWeatherPart(string weather)
{
// could do nothing by default
_complexProduct.ValueDependOnWeather = weather;
} public virtual void BuildValueDependOnFortunePart(string luck)
{
// could do nothing by default
_complexProduct.ValueDependOnFortune = luck;
} public ComplexProduct EndBuild()
{
return this._complexProduct;
}
} public class ConcreteProductBuilderA : AbstractComplexProductBuilder
{
private string _dayOfWeek;
private int _luckyNumber; public ConcreteProductBuilderA(string dayOfWeek, int luckyNumber)
{
_dayOfWeek = dayOfWeek;
_luckyNumber = luckyNumber;
} public override void BuildValueDependOnWeatherPart(string weather)
{
// something customized
_complexProduct.ValueDependOnWeather = _dayOfWeek + " is " + weather;
} public override void BuildValueDependOnFortunePart(string luck)
{
// something customized
if (_luckyNumber == )
_complexProduct.ValueDependOnFortune = "Supper" + luck;
else
_complexProduct.ValueDependOnFortune = "Just so so" + luck;
}
} public class GoodWeatherAndGoodLuckDirector
{
public void ConstructWithGoodWeatherAndGoodLuck(AbstractComplexProductBuilder builder)
{
builder.BuildValueDependOnWeatherPart(@"PM2.5 < 50");
builder.BuildValueDependOnFortunePart(@"Good Luck");
} public void ConstructWithBadWeatherAndBadLuck(AbstractComplexProductBuilder builder)
{
builder.BuildValueDependOnWeatherPart(@"PM2.5 > 500");
builder.BuildValueDependOnFortunePart(@"Bad Luck");
}
} public class Client
{
public void TestCase1()
{
AbstractComplexProductBuilder builder = new ConcreteProductBuilderA("Sunday", );
GoodWeatherAndGoodLuckDirector director = new GoodWeatherAndGoodLuckDirector(); builder.BeginBuild();
director.ConstructWithGoodWeatherAndGoodLuck(builder);
ComplexProduct productWithGoodLuck = builder.EndBuild(); builder.BeginBuild();
director.ConstructWithBadWeatherAndBadLuck(builder);
ComplexProduct productWithBadLuck = builder.EndBuild();
}
}
}
实现方式(二):Builder 将构件返回给 Director,Director 将构件传递给 Builder 中的下一个步骤。
Builder 逐步的构造产品,所以其接口必须足够的普遍。如果构造过程中需要访问前面已经构造了的产品构件,则 Builder 将构件返回给 Director,由 Director 将构件传递给 Builder 中的下一个步骤。
namespace BuilderPattern.Implementation2
{
public class ComplexProduct
{
public string ValueDependOnWeather { get; set; }
public string ValueDependOnFortune { get; set; }
} public abstract class AbstractComplexProductBuilder
{
protected ComplexProduct _complexProduct; public void BeginBuild(ComplexProduct existingComplexProduct = null)
{
if (existingComplexProduct == null)
_complexProduct = new ComplexProduct();
else
_complexProduct = existingComplexProduct;
} public virtual string BuildValueDependOnWeatherPart(string weather)
{
// could do nothing by default
_complexProduct.ValueDependOnWeather = weather;
return _complexProduct.ValueDependOnWeather;
} public virtual string BuildValueDependOnFortunePart(string luck, string combinedWithWeather)
{
// could do nothing by default
_complexProduct.ValueDependOnFortune = luck + combinedWithWeather;
return _complexProduct.ValueDependOnFortune;
} public ComplexProduct EndBuild()
{
return this._complexProduct;
}
} public class ConcreteProductBuilderA : AbstractComplexProductBuilder
{
private string _dayOfWeek;
private int _luckyNumber; public ConcreteProductBuilderA(string dayOfWeek, int luckyNumber)
{
_dayOfWeek = dayOfWeek;
_luckyNumber = luckyNumber;
} public override string BuildValueDependOnWeatherPart(string weather)
{
// something customized
_complexProduct.ValueDependOnWeather = _dayOfWeek + " is " + weather;
return _complexProduct.ValueDependOnWeather;
} public override string BuildValueDependOnFortunePart(string luck, string combinedWithWeather)
{
// something customized
if (_luckyNumber == )
_complexProduct.ValueDependOnFortune = "Supper" + luck + combinedWithWeather;
else
_complexProduct.ValueDependOnFortune = "Just so so" + luck + combinedWithWeather;
return _complexProduct.ValueDependOnFortune;
}
} public class GoodWeatherAndGoodLuckDirector
{
public void ConstructWithGoodWeatherAndGoodLuck(AbstractComplexProductBuilder builder)
{
string weather = builder.BuildValueDependOnWeatherPart(@"PM2.5 < 50");
builder.BuildValueDependOnFortunePart(@"Good Luck", weather);
} public void ConstructWithBadWeatherAndBadLuck(AbstractComplexProductBuilder builder)
{
string weather = builder.BuildValueDependOnWeatherPart(@"PM2.5 > 500");
builder.BuildValueDependOnFortunePart(@"Bad Luck", weather);
}
} public class Client
{
public void TestCase2()
{
AbstractComplexProductBuilder builder = new ConcreteProductBuilderA("Sunday", );
GoodWeatherAndGoodLuckDirector director = new GoodWeatherAndGoodLuckDirector(); builder.BeginBuild();
director.ConstructWithGoodWeatherAndGoodLuck(builder);
ComplexProduct productWithGoodLuck = builder.EndBuild(); builder.BeginBuild();
director.ConstructWithBadWeatherAndBadLuck(builder);
ComplexProduct productWithBadLuck = builder.EndBuild();
}
}
}
《设计模式之美》为 Dennis Gao 发布于博客园的系列文章,任何未经作者本人同意的人为或爬虫转载均为耍流氓。
设计模式之美:Builder(生成器)的更多相关文章
- 设计模式03: Builder 生成器模式(创建型模式)
Builder生成器模式(创建型模式) Builder模式缘起假设创建游戏中的一个房屋House设施,该房屋的构建由几个部分组成,且各个部分富于变化.如果使用最直观的设计方法,每个房屋部分的变化,都将 ...
- 面向对象设计模式纵横谈:Builder 生成器模式(笔记记录)
Builder模式的缘起 假设创建游戏中的一个房屋House设施,该房屋的构建由几个部分组成,且各个部分要富于变化. 如果使用最直观的设计方法,每一个房屋部分的变化,都将导致房屋构建的重新修正…… 动 ...
- C#面向对象设计模式纵横谈——4.Builder 生成器模式(创建型模式)
动机 (Motivation) 在软件系统中,有时候面临着“一个复杂对象”的创建工作,其通常由各个部分的子对象用一定的算法构成:由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是它们组合 ...
- 设计模式之美:Creational Patterns(创建型模式)
创建型模式(Creational Patterns)抽象了对象实例化过程. 它们帮助一个系统独立于如何创建.组合和表示它的那些对象. 一个类创建型模式使用继承改变被实例化的类. 一个对象创建型模式将实 ...
- Builder生成器(创建型模式)
一.使用场景: 1.假设要创建一个House设施,该设施的创建由若干个部分组成,而且这若干个部分经常变化. 如果用最直观的设计方式,每一个房屋部分的变化,都将导致整个房屋结构的重新修正,但是这种设计方 ...
- 设计模式之美:Product Trader(操盘手)
索引 意图 结构 参与者 适用性 效果 相关模式 实现 实现方式(一):Product Trader 的示例实现. 意图 使客户程序可以通过命名抽象超类和给定规约来创建对象. Product Trad ...
- 设计模式之美:Null Object(空对象)
索引 意图 结构 参与者 适用性 效果 相关模式 实现 实现方式(一):Null Object 的示例实现. 意图 通过对缺失对象的封装,以提供默认无任何行为的对象替代品. Encapsulate t ...
- 设计模式之美:Dynamic Property(动态属性)
索引 别名 意图 结构 参与者 适用性 效果 实现 实现方式(一):Dynamic Property 的示例实现. 别名 Property Properties Property List 意图 使对 ...
- 设计模式之美:Role Object(角色对象)
索引 意图 结构 参与者 适用性 效果 相关模式 实现 实现方式(一):Role Object 的示例实现. 意图 通过明确地附加角色对象到目标对象中,以使对象可以适配不同的客户需求.每个角色对象都代 ...
随机推荐
- 块级格式化上下文(block formatting context)、浮动和绝对定位的工作原理详解
CSS的可视化格式模型中具有一个非常重要地位的概念——定位方案.定位方案用以控制元素的布局,在CSS2.1中,有三种定位方案——普通流.浮动和绝对定位: 普通流:元素按照先后位置自上而下布局,inli ...
- windows2008r2环境双实例安装mysql5.6
windows2008r2环境双实例安装mysql5.6 环境:windows2008 r2 标准版 1.默认安装了一个mysql5.6端口为3306 2.使用msi文件安装需要.net4.0支持,安 ...
- HP XP7 GAD双活实现的理解
XP7双活的虚拟卷global active device (GAD)实际上对应两个存储的两个物理卷(有点儿像Mirror Disk镜像) 当主机A向阵列A发出写数据请求后,阵列A首先检查要被写入的数 ...
- select、epoll、twisted网络编程
select.poll和epoll的区别 select select最早于1983年出现在4.2BSD中,它通过一个select()系统调用来监视多个文件描述符的数组,当select()返回后,该数组 ...
- 初识Memcached
一,什么是memcached? Memcached是一个高性能的分布式内存对象缓存系统,用于动态web应用以减轻数据库负载..它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态.数据库驱 ...
- WebForm---增删改(内置对象)
一.添加 前台代码: <body> <form id="form1" runat="server"> <h1>用户添加< ...
- c 数据拼接
char buf1[] = {0x31,0x32,0x33,0x00,0x51,0x52,0x53,0xaa,0xbb,0xcc,0x00}; int a=0xabcd6799; int b=0x88 ...
- js导入外部脚本文件
JS 语言没找到导入外部脚本文件的功能,只能通知宿主程序来处理. function include(path){ var a=document.createElement("script&q ...
- VMware下 Ubuntu 看不到共享文件夹之解决办法
VMware下 Ubuntu 看不到共享文件夹之解决办法 初学Linux,在VMWare 上装了Ubuntu10.04,主机端和虚拟机相互间的访问是必不可少的,途径有许多,其中vmware tool提 ...
- 如何扫描二维码下载APK
将apk文件放到网站上,即用户可以通过www.xxx.com.cn/abc.apk直接下载 再www.xxx.com.cn/abc.apk这个字符串做成二维码就可以了. 问题: 直接放到网站后,输入下 ...