设计模式之美: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 的示例实现. 意图 通过明确地附加角色对象到目标对象中,以使对象可以适配不同的客户需求.每个角色对象都代 ...
随机推荐
- Scrum 项目——1
广商检索页面 1) N (Need 需求) 这个页面会按一定的规律来集合广商的一些资源,包括微信公众号.教务系统登录处.宿舍报修等,是为了方便我们整个广商的学生和老师来运用.因为现在虽然有很多微信公众 ...
- 【转载】OpenGL超级宝典笔记——GLSL语言基础
变量 GLSL的变量命名方式与C语言类似.变量的名称可以使用字母,数字以及下划线,但变量名不能以数字开头,还有变量名不能以gl_作为前缀,这个是GLSL保留的前缀,用于GLSL的内部变量.当然还有一些 ...
- javascript作用域和作用域链摘录
作用域是JavaScript最重要的概念之一,想要学好JavaScript就需要理解JavaScript作用域和作用域链的工作原理.今天这篇文章对JavaScript作用域和作用域链作简单的介绍,希望 ...
- oracle rownum paging issues
rownum是oracle预处理字段,默认标序是1,只有记录集已经满足条件后才会进行后续编号.由于第一条记录rownum默认是1,而你的条件是rownum>=6 对第一条记录比较它的rownum ...
- CSS BOX模型
对于box模型概念的理解以及它与决定元素最终尺寸的方式有何关系,是理解如何设定网 页上的元素位置的基础.box模型应用到块级元素.一个随之而来的概念,内联布局模型 定义了如何设定内联元素的位置. 对于 ...
- python 注册
1.打开网址,点击 获得注册码 http://idea.qinxi1992.cn/ 2.help -- register 第二步: http://jetbrains.tencent.click/ ...
- 解决方法:An error occurred on the server when processing the URL. Please contact the system administrator
在WINDOWS7或SERVER2008上安装了IIS7.5,调试ASP程序时出现以下错误: An error occurred on the server when processing the U ...
- Selenium2+python自动化11-定位一组元素find_elements
前言 前面的几篇都是讲如何定位一个元素,有时候一个页面上有多个对象需要操作,如果一个个去定位的话,比较繁琐,这时候就可以定位一组对象. webdriver 提供了定位一组元素的方法,跟前面八种定位方式 ...
- RHEL 7.0 本地配置yum源
RHEL 7.0 本地配置yum源 yum简介 yum = Yellow dog Updater, Modified 主要功能是更方便的添加/删除/更新RPM包. 它能自动解决包的倚赖性问题. 它 ...
- access数据库连接问题
使用Visual Studio连接access数据库(数据库后缀.accdb)时连接不上(access数据库提示未在本地计算机上注册“Microsoft.ACE.OLEDB.12.0”提供程序)解决办 ...