C#设计模式学习笔记:(4)建造者模式
本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/7614630.html,记录一下学习过程以备后续查用。
一、引言
在现实生活中,我们经常会遇到一些构成比较复杂的物品。比如电脑,是由CPU、主板、内存条、硬盘、显卡、机箱等组装而成的。手机也是复杂物品,
由主板、各种芯片、RAM、ROM、摄像头等部件组成。但是无论是电脑还是手机,它们的组装过程是固定的。拿手机来说,组装流水线是固定的、不变的,
但是把不同的主板和其它组件组装在一起就会生产出不同型号的手机。那么在软件系统中是不是也会存在这样的对象呢?答案是肯定的。在软件系统中我们
也会遇到类似的复杂对象,并且这个复杂对象的各个部分按照一定的算法组合在一起,此时该对象的创建工作就可以使用Builder模式了,下面让我们详细看
看这个模式吧。
二、建造者模式介绍
建造者模式(也叫生成器模式):英文名称--Builder Pattern;分类--创建型。
2.1、动机(Motivate)
在软件系统中,有时候面临着“一个复杂对象”的创建工作,其通常由各个部分的子对象用一定的算法构成。由于需求的变化,这个复杂对象的各个部分经
常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。如何应对这种变化?如何提供一种“封装机制”来隔离出“复杂对象的各个部分”的变化,从
而保持系统中的“稳定构建算法”不随着需求改变而改变?
2.2、意图(Intent)
将一个复杂对象的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。——《设计模式》GoF
2.3、结构图(Structure)
2.4、模式的组成
1)抽象建造者角色(Builder):为创建一个Product对象的各个部件指定抽象接口,以规范产品对象的各个组成部分的建造。一般而言,此角色规定要实
现复杂对象的哪些部件的创建,并不涉及具体的对象部件的创建。
2)具体建造者(ConcreteBuilder)
I、实现Builder的接口以构造和装配该产品的各个部件,即实现抽象建造者角色Builder的方法。
II、定义并明确它所创建的表示,即针对不同的商业逻辑,具体化复杂对象的各个部分的创建。
III、提供一个检索产品的接口。
IV、构造一个使用Builder接口的对象,即在指导者的调用下创建产品实例。
3)指导者(Director):调用具体建造者角色以创建产品对象的各个部分。指导者并没有涉及具体产品类的信息,真正拥有具体产品的信息是具体建造者
对象。它只负责保证对象各部分完整创建或按某种顺序创建。
4)产品角色(Product):建造中的复杂对象。它要包含那些定义组件的类,包括将这些组件装配成产品的接口。
2.5、建造者模式的具体实现
现在人们生活水平都提高了,家家都有了家庭轿车,那今天我们就以汽车组装为例来说明Builder模式的实现。
class Program
{
/// <summary>
/// 小轿车类
/// </summary>
public sealed class SaloonCar
{
//小轿车部件集合
private IList<string> parts = new List<string>(); //把单个部件添加到小轿车部件集合中
public void Add(string part)
{
parts.Add(part);
} public void Show()
{
Console.WriteLine("小轿车开始组装.......");
foreach (string part in parts)
{
Console.WriteLine("部件[" + part + "]已组装。");
} Console.WriteLine("小轿车组装完毕。");
}
} /// <summary>
/// 抽象建造者,它定义了要创建什么部件和最后创建的结果,但是不是组装的的类型,切记。
/// </summary>
public abstract class Builder
{
//创建车门
public abstract void BuildSaloonCarDoor();
//创建车轮
public abstract void BuildSaloonCarWheel();
//创建车引擎
public abstract void BuildSaloonCarEngine();
//获得组装好的小轿车
public abstract SaloonCar GetSaloonCar();
} /// <summary>
/// 具体创建者,具体车型的创建者,例如:别克。
/// </summary>
public sealed class BuickBuilder : Builder
{
SaloonCar buickCar = new SaloonCar();
public override void BuildSaloonCarDoor()
{
buickCar.Add("Buick's door");
} public override void BuildSaloonCarWheel()
{
buickCar.Add("Buick's wheel");
} public override void BuildSaloonCarEngine()
{
buickCar.Add("Buick's engine");
} public override SaloonCar GetSaloonCar()
{
return buickCar;
}
} /// <summary>
/// 具体创建者,具体车型的创建者,例如:奥迪
/// </summary>
public sealed class AoDiBuilder : Builder
{
SaloonCar aoDiCar = new SaloonCar();
public override void BuildSaloonCarDoor()
{
aoDiCar.Add("Aodi's door");
} public override void BuildSaloonCarWheel()
{
aoDiCar.Add("Aodi's wheel");
} public override void BuildSaloonCarEngine()
{
aoDiCar.Add("Aodi's engine");
} public override SaloonCar GetSaloonCar()
{
return aoDiCar;
}
} /// <summary>
/// 这个类型才是组装的
/// Construct方法里面的实现就是创建复杂对象固定算法的实现,该算法是固定的或者说是相对稳定的。
/// 这个人当然就是老板了,也就是建造者模式中的指挥者。
/// </summary>
public class Director
{
//组装汽车
public void Construct(Builder builder)
{
builder.BuildSaloonCarDoor();
builder.BuildSaloonCarWheel();
builder.BuildSaloonCarEngine();
}
} static void Main(string[] args)
{
#region 建造者模式
Director director = new Director();
Builder buickBuilder = new BuickBuilder();
Builder aoDiBuilder = new AoDiBuilder(); //组装别克小轿车
director.Construct(buickBuilder);
SaloonCar buickCar = buickBuilder.GetSaloonCar();
buickCar.Show(); Console.WriteLine(); //组装奥迪小轿车
director.Construct(aoDiBuilder);
SaloonCar aoDiCar = aoDiBuilder.GetSaloonCar();
aoDiCar.Show(); Console.Read();
#endregion
}
}
运行结果如下:
三、建造者模式的实现要点
在建造者模式中,指挥者是直接与客户端打交道的。指挥者将客户端创建产品的请求转换为对各个部件的建造请求,再将这些请求委派给具体的建造者角
色,而具体的建造者角色是完成具体产品的构建工作的,却不为客户所知道。
建造者模式主要用于“分步骤来构建一个复杂的对象”,其中“分步骤”是一个固定的组合过程,而复杂对象的各个部分是经常变化的。 产品不需要抽象类,
因为建造者模式创建出来的最终产品可能差异很大,所以不大可能提炼出一个抽象产品类。 在前面文章中介绍的抽象工厂模式解决了“多系列产品”的需求变
化,而建造者模式解决的是 “产品部分” 的需要变化。 由于建造者隐藏了具体产品的组装过程,所以要改变一个产品的内部表示,只需要再实现一个具体的
建造者就可以了,从而能很好地应对产品组成部件的需求变化。
3.1、建造者模式的优点
1)使用建造者模式可以使客户端不必知道产品内部组成的细节。
2)具体的建造者类之间是相互独立的,容易扩展。
3)由于具体的建造者是独立的,因此可以对建造过程逐步细化,而不对其他的模块产生任何影响。
3.2、建造者模式的缺点
1)产生多余的Build对象以及Dirextor类。
3.3、创建者模式的使用场合
1)当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。
2)相同的方法,不同的执行顺序,产生不同的事件结果时。
3)多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同时。
4)产品类非常复杂,或者产品类中的调用顺序不同产生了不同的效能。
5)创建一些复杂的对象时,这些对象的内部组成构件间的建造顺序是稳定的,但是对象的内部组成构件面临着复杂的变化。
四、.NET中建造者模式的实现
微软的类库里面大量使用了设计模式,如果要想学习设计模式,仔细看看微软的类库是很有帮助的。今天的设计模式在FCL里面也有实现,该类型的名字
是System.Text.StringBuilder(存在于mscorlib.dll程序集中),它就是一个建造者模式的实现,从名称也可以看出来。不过它的实现属于建造者模式的演化,此时
的建造者模式没有指挥者角色和抽象建造者角色,StringBuilder类既扮演着具体建造者的角色,也同时扮演了指挥者和抽象建造者的角色。
StringBuilder类扮演着建造string对象的具体建造者角色,其中的ToString()方法用来返回具体产品给客户端(相当于上面代码中GetSaloonCar方法)。其中
Append方法用来创建产品的组件(相当于上面代码中Add方法),因为string对象中每个组件都是字符,所以也就不需要指挥者角色的代码(如上面代码中的
Construct方法),Append方法也充当了指挥者Construct方法的作用。
五、总结
需要重申的是,学习设计模式不能死学,就像StringBuilder一样,他和Gof23种设计模式中定义的情形有很大的不同,但是它也是Builder模式,因为它要解决
的问题和使用场景是吻合的。我们写代码的时候,不要太居于形式,要看使用的契机和模式是否吻合,根据具体的情况我们的模式也会发生变化。当我们看得越
多也写得越多的时候,变化就越自然了。
C#设计模式学习笔记:(4)建造者模式的更多相关文章
- 设计模式学习笔记--备忘录(Mamento)模式
写在模式学习之前 什么是设计模式:在我们进行程序设计时,逐渐形成了一些典型问题和问题的解决方式,这就是软件模式:每个模式描写叙述了一个在我们程序设计中常常发生的问题,以及该问题的解决方式:当我们碰到模 ...
- 设计模式学习笔记-Adapter模式
Adapter模式,就是适配器模式,使两个原本没有关联的类结合一起使用. 平时我们会经常碰到这样的情况,有了两个现成的类,它们之间没有什么联系,但是我们现在既想用其中一个类的方法,同时也想用另外一个类 ...
- Java-马士兵设计模式学习笔记-装饰者模式
Java装饰者模式简介 一.假设有一个Worker接口,它有一个doSomething方法,Plumber和Carpenter都实现了Worker接口,代码及关系如下: 1.Worker.java p ...
- 研磨设计模式学习笔记2--外观模式Facade
需求:客户端需要按照需求,执行一个操作,操作包括一个系统中的3个模块(根据配置选择是否全部执行). 外观模式优点: 客户端无需知道系统内部实现,,只需要写好配置文件,控制那些模块执行,简单易用. 外观 ...
- 设计模式学习笔记 1.factory 模式
Factory 模式 用户不关心工厂的具体类型,只知道这是一个工厂就行. 通过工厂的实现推迟到子类里面去来确定工厂的具体类型. 工厂的具体类型来确定生产的具体产品. 同时用户不关心这是一个什么样子的产 ...
- 设计模式学习笔记——Composite 组合模式
用于描述无限层级的复杂对象,类似于描述资源管理器,抽象出每一个层级的共同特点(文件夹和文件,展开事件) 以前描述一个对象,是将整个对象的全部数据都描述清楚,而组合模式通过在对象中定义自己,描述自己的下 ...
- 设计模式学习笔记——Bridge 桥接模式
先说一下我以前对桥接模式的理解:当每个类中都使用到了同样的属性或方法时,应该将他们单独抽象出来,变成这些类的属性和方法(避免重复造轮子),当时的感觉是和三层模型中的model有点单相似,也就是让mod ...
- 设计模式学习笔记——Visitor 访问者模式
1.定义IVisitor接口,确定变化所涉及的方法 2.封装变化类.实现IVisitor接口 3.在实体类的变化方法中传入IVisitor接口,由接口确定使用哪一种变化来实现(封装变化) 4.在使用时 ...
- Java-马士兵设计模式学习笔记-责任链模式-FilterChain功能
一.目标 增加filterchain功能 二.代码 1.Filter.java public interface Filter { public String doFilter(String str) ...
- Java-马士兵设计模式学习笔记-责任链模式-处理数据
一.目标 数据提交前做各种处理 二.代码 1.MsgProcessor.java public class MsgProcessor { private List<Filter> filt ...
随机推荐
- 转载---class文件中的字段表集合--field字段在class文件中是怎样组织的
写的太好了! https://blog.51cto.com/1459294/1932331
- 手把手写框架入门(一) | 核心拦截器DispatchFilter实现
前言 1Filter实现框架拦截 1配置自定义Filter 2创建一个Filter 3创建一个ActionMapping 4创建一个ActionMapper 5创建一个WebExecutor 6创建测 ...
- artTemplate--模板使用自定义函数(1)
案例 因为公司业务需要频繁调用接口,后端返回的都是json树对象,需要有些特殊的方法做大量判断和数据处理,显然目前简单语法已经不能满足业务需要了,需要自己定制一些 方法来处理业务逻辑. 例如后台返回的 ...
- Spring AOP源码分析--代理方式的选择
能坚持别人不能坚持的,才能拥有别人未曾拥有的.关注编程大道公众号,让我们一同坚持心中所想,一起成长!! 年前写了一个面试突击系列的文章,目前只有redis相关的.在这个系列里,我整理了一些面试题与大家 ...
- 第三次作业:使用Packet Tracer分析TCP连接的建立与释放过程
0 个人信息 张樱姿 201821121038 计算1812 1 实验目的 使用路由器连接不同的网络 使用命令行操作路由器 通过抓取HTTP报文,分析TCP连接建立的过程 2 实验内容 使用Packe ...
- HDU_5094_dfs
http://acm.hdu.edu.cn/showproblem.php?pid=5094 bfs,vis[x][y][z],z表示钥匙的状态,用二进制来表示,key[x][y]储存当前位置钥匙的二 ...
- constrainlayout布局
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/r ...
- 自学笔记系列:《Python学习手册 第五版》 -写在开始之前
今年双十一,在当当网上买了这本书,很厚很厚的一本书,大概有将近1700页左右,的确是一个“大工程”, 关于这本书的学习,我想采用一种博客的方式进行,既是写给自己,也想分享给每一个对Python学习感兴 ...
- DataGuard---->主库和备库都配置 db_file_name_convert和log_file_name_convert的作用
一.参数说明 [1] db_file_name_convert db_file_name_convert 主数据库和备用数据库的数据文件转换目录对映(如果两数据库的目录结构不一样),如果有多个对映,逐 ...
- Spring事务中的隔离级别
TransactionDefinition接口中定义了五个表示隔离级别的常量: TransactionDefinition.ISOLATION_DEFAULT:使用后端数据库默认的隔离界别,MySQL ...