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 ...
随机推荐
- 不停机替换线上代码? 你没听错,Arthas它能做到
写在前边 有没有这样一种感受,自己写的代码在开发.测试环境跑的稳得一笔,可一到线上就抽风,不是缺这个就是少那个反正就是一顿报错,线上调试代码又很麻烦,让人头疼得很.阿里巴巴出了一款名叫Arthas的工 ...
- 异常处理 | manual close is not allowed over a Spring managed SqlSession
背景: 今天启动一个老项目,控制台打印出以下异常,大概是说在Spring托管的SqlSession上不允许手动关闭: java.lang.UnsupportedOperationException: ...
- html网页压缩保存到数据库,减少空间占用,实现过程遇到的解压问题
场景: python获取到网页,把网页gzip打包,并Base64编码保存: 由java负责Base64解码并解压二进制成html 遇到的问题: 1.python 的request,缺省就把gzip响 ...
- 教你5分钟做个手机APP[视频]
天天宅在家里,没什么事做,录个教学视频吧! 发到了视频网站上去根本没人看,伤心ing啊! 不知cnblogs上面是否让我发! 先上一张效果图看看哈: 如果播放不正常请点这里:https://www.b ...
- Java中正确终止线程的方法
Thread类中有一个已经废弃的 stop() 方法,它可以终止线程,但由于它不管三七二十一,直接终止线程,所以被废弃了.比如,当线程被停止后还需要进行一些善后操作(如,关闭外部资源),使用这个方法就 ...
- 5G为人工智能与工业互联网赋能 高清79页PPT
人工智能和5G是时下最热门的科技领域之一,两者都是能改变社会,推进下一代工业革命的颠覆性技术. 工业互联网是利用基础科学.工业.信息技术.互联网等领域的综合优势,从大数据应用等软服务切入,注重软件.网 ...
- 一次修改数据库物理文件造成Mysql宕机的恢复记录
事件起始 某夜,我正在床上冥想准备入睡,忽然同事向我求救:消息内容如下: Oh My Gold 改了些配置,啥都没了!都没了!没了!了! 我仔细询问,原来是她因为某些原因将某库的物理文件夹改名后,发现 ...
- [redis读书笔记] 第二部分 sentinel
1.sentinel的初始化,会制定master的IP和port,然后sentinel会创建向被监视主服务器的命令连接和订阅连接: - 命令连接是用来和主服务器之间进行命令通信的 - 订阅连接,用于 ...
- 02-Redis
今日内容 1. redis 1. 概念 2. 下载安装 3. 命令操作 1. 数据结构 4. 持久化操作 5. 使用Java客户端操作redis Redis 1. 概念:redis是一款高性能的NOS ...
- python-nmap 使用
安装 [root@localhost ~]# yum -y install nmap [root@localhost ~]# pip install python-nmap 使用 import nma ...