c#中建造者设计模式详解
基础介绍:
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
说白了就是将一个复杂的对象拆分成一个一个零件,然后按照既定顺序和规则进行组装,最终形成这个相对复杂的对象。
具体可分为4个角色:
Product(产品):复杂对象本身。
Builder(抽象建造者):既可以是抽象类也可以是接口,主要是为了约束和规范具体建造者有哪些零件,并提供一个方法返回组装后的复杂对象。
ConcreteBuilder(具体建造者):它继承自Builder(抽象建造者),主要是具体实现父类中的那些零件。也就是说在这个类里就要实际去创建各个零件的具体功能了。
Director(指挥者):又称为导演类,在指挥者中不涉及具体产品的信息,只负责保证对象各部分完整创建或按某种顺序创建。客户端一般只需要与指挥者进行交互,在客户端确定具体建造者的类型,并实例化具体建造者对象,然后通过指挥者类的构造函数或者Setter方法将该对象传入指挥者类中。
- 特性和功能:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
- 使用环境:当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。
- 注意事项:建造者模式的使用需要考虑其复杂性,如果产品结构较简单,使用此模式可能会增加系统的复杂性。
- 优点:客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦。
- 缺点:产品的组成部分必须相同,限制了其使用范围。
应用场景:
有时需要创建一个复杂对象,其通常由其各部分子对象通过一定的步骤组合而成。
由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。
本质就是:创建的对象较复杂,由多个部件构成,各部件面临着复杂的变化,但构件间的建造顺序是稳定的。
使得相同的创建过程可以创建不同的产品。
造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,则不适合使用建造者模式。
- 垃圾食品套餐系统:汉堡、可乐、薯条、炸鸡翅等是不变的,而其组合是经常变化的,生成出各种特惠"套餐"。
- 装修系统:改水电、再贴瓷砖、家电、电视墙等,顺序基本不变,用材不同最终生成的产品则不同。
- ......
创建方式:
本实例主要是中Computer是产品,包含CPU、主板、内存、硬盘、显卡、机箱等组件。
Builder是抽象建造者,HighPerformanceBuilder和CostEffectiveBuilder是具体的建造者,Director是指挥者。
首先要确定产品类

1 /// <summary>
2 /// 产品类
3 /// </summary>
4 public class Computer
5 {
6 public string CPU { get; set; }
7 public string Memory { get; set; }
8 public string Disk { get; set; }
9 }其次是抽象建造者类

1 /// <summary>
2 /// 抽象建造者类
3 /// </summary>
4 public abstract class BuilderComputer
5 {
6 //产品对象---protected关键字受保护成员可以在其所在的类、其子类以及同一个命名空间中的其他类中被访问。
7 protected Computer computer = new Computer();
8
9 //以下方法约束了产品由哪些零件组成
10 public abstract void BuildCPU();
11 public abstract void BuildMemory();
12 public abstract void BuildDisk();
13
14 /// <summary>
15 /// 返回对象本身
16 /// </summary>
17 /// <returns></returns>
18 public Computer GetComputer()
19 {
20 return computer;
21 }
22 }该类中限定了产品的组成部分也就是各个零件。
这里指明了产品由三个零件组成,分别是CPU、Disk和Memory。
再者是具体建造者类

1 /// <summary>
2 /// 低配电脑 具体的创建者
3 /// </summary>
4 class LowComputer : BuilderComputer
5 {
6 public override void BuildCPU()
7 {
8 computer.CPU = "i5处理器";
9 }
10
11 public override void BuildDisk()
12 {
13 computer.Disk = "512G固态";
14 }
15 public override void BuildMemory()
16 {
17 computer.Memory = "16G内存";
18 }
19 }
20
21 /// <summary>
22 /// 高配电脑 具体的创建者
23 /// </summary>
24 class GoodComputer : BuilderComputer
25 {
26 public override void BuildCPU()
27 {
28 computer.CPU = "i7处理器";
29 }
30
31 public override void BuildDisk()
32 {
33 computer.Disk = "1T固态";
34 }
35 public override void BuildMemory()
36 {
37 computer.Memory = "32G内存";
38 }
39 }上述代码中定义了两个具体建造者,分别是低配电脑和高配电脑。
继承自抽象建造者类,并具体实现了其中的零件。
如果还有还想新增其他配置点电脑,就可以新增一个具体建造者类,而无需修改其他代码。
最后是指挥者

1 /// <summary>
2 /// 指挥者-监工 创建对象的顺序
3 /// </summary>
4 public class Director
5 {
6 private BuilderComputer _builder = null;
7
8 /// <summary>
9 /// 通过构造函数传递具体创造者
10 /// </summary>
11 /// <param name="builder"></param>
12 public Director(BuilderComputer builder)
13 {
14 this._builder = builder;
15 }
16
17 /// <summary>
18 /// 组装方法,并返回产品
19 /// </summary>
20 /// <returns></returns>
21 public Computer AssembleComputer()
22 {
23 _builder.BuildCPU();
24 _builder.BuildDisk();
25 _builder.BuildMemory();
26 return _builder.GetComputer();
27 }
28 }在上述代码中是通过构造函数传递具体创造者,也可以在AssembleComputer方法中传递。
产品的具体组装规则则是由AssembleComputer方法来完成,如果有多种组装方式,也可以有多个方法来分别完成。
该类本质就是统筹安排,并直接与客户端进行交互。
- 客户端调用

1 class Program
2 {
3 static void Main(string[] args)
4 {
5 Console.WriteLine("我想组装一台低配电脑:");
6 //首先实例化一个低配电脑的具体建造对象
7 BuilderComputer builderComputer = new LowComputer();
8 //然后使用指挥者类来具体组装这个产品
9 Computer director = new Director(builderComputer).AssembleComputer();
10 Console.WriteLine("组装完毕,具体配置如下:");
11 Console.WriteLine(director.CPU);
12 Console.WriteLine(director.Memory);
13 Console.WriteLine(director.Disk);
14
15
16 Console.WriteLine("\n我又想组装一台高配电脑:");
17 //首先实例化一个高配电脑的具体建造对象
18 builderComputer = new GoodComputer();
19 //然后使用指挥者类来具体组装这个产品
20 director = new Director(builderComputer).AssembleComputer();
21 Console.WriteLine("组装完毕,具体配置如下:");
22 Console.WriteLine(director.CPU);
23 Console.WriteLine(director.Memory);
24 Console.WriteLine(director.Disk);
25
26 }
27 }
- 指挥者类也可以省略,组装交给抽奖建造者来完成

1 /// <summary>
2 /// 抽象建造者类
3 /// </summary>
4 public abstract class BuilderComputer
5 {
6 //产品对象---protected关键字受保护成员可以在其所在的类、其子类以及同一个命名空间中的其他类中被访问。
7 protected Computer computer = new Computer();
8
9 //以下方法约束了产品由哪些零件组成
10 public abstract void BuildCPU();
11 public abstract void BuildMemory();
12 public abstract void BuildDisk();
13
14 /// <summary>
15 /// 可以省略掉指挥者类,由此方法进行组装
16 /// </summary>
17 /// <returns></returns>
18 public Computer Construct()
19 {
20 this.BuildCPU();
21 this.BuildMemory();
22 this.BuildDisk();
23 return computer;
24 }
25 }
1 class Program
2 {
3 static void Main(string[] args)
4 {
5 Console.WriteLine("我想组装一台低配电脑:");
6 Computer director = new LowComputer().Construct();
7 Console.WriteLine("组装完毕,具体配置如下:");
8 Console.WriteLine(director.CPU);
9 Console.WriteLine(director.Memory);
10 Console.WriteLine(director.Disk);
11
12
13 Console.WriteLine("\n我又想组装一台高配电脑:");
14 director = new GoodComputer().Construct();
15 Console.WriteLine("组装完毕,具体配置如下:");
16 Console.WriteLine(director.CPU);
17 Console.WriteLine(director.Memory);
18 Console.WriteLine(director.Disk);
19
20 }
21 }在上述代码中可以看出,此处还可以定义了一个虚方法,
在具体建造者中,可以根据需要重写该方法,使其返回实际需要的值,然后在构建过程中,使用该值进行构建。相较于指挥者类,具体产品的组装可以交由产品本身去组装。
总结:
建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,并不适合使用建造者模式。
建造者隐藏了具体产品的组装过程,所以要改变一个产品的内部表示,只需要再实现一个具体的建造者就可以了,从而能很好地应对产品组成组件的需求变化。
需要生产的产品对象有复杂的内部结构,这些产品对象通常包含多个成员变量,产品对象的属性相互依赖,需要指定其生成顺序。
对象的创建过程独立于创建该对象的类,隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的产品。
附:创建者模式对比
工厂模式解决了“同一类产品”的需求变化,抽象工厂模式解决了“系列产品”的需求变化,而建造者模式解决的是 “产品部分” 的需要变化。
工厂方法模式 VS 建造者模式
工厂方法模式侧重整体对象的创建方式,建造者模式侧重零部件的构建,然后通过一定顺序和规则构造出一个复杂的对象。
例如:想要制作一个假人,如果使用工厂方法模式,直接生产出来一个XX材质、XX高、XX重的假人人就可以了。
而如果使用建造者模式,则需要先创建出四肢、头和躯干等部位,然后按照一定顺序进行组装形成一个完整的假人。
抽象工厂模式 VS 建造者模式
抽象工厂模式侧重对产品族(系列产品)的创建,一个产品族是这样的一系列产品。
采用抽象工厂模式不需要关心构建过程,只关心什么产品由什么工厂生产即可。
建造者模式则侧重要求按照指定的蓝图建造产品,它的主要目的是通过组装零配件而产生一个新产品。
如果将抽象工厂模式看成汽车配件生产工厂,生产一个产品族的产品,那么建造者模式就是一个汽车组装工厂,通过对部件的组装可以返回一辆完整的汽车。
c#中建造者设计模式详解的更多相关文章
- 【建造者设计模式详解】Java/JS/Go/Python/TS不同语言实现
简介 建造者模式(Builder Pattern),也叫生成器模式,属于创建型模式.它使用多个简单的对象一步一步构建成一个复杂的对象.它允许你使用相同的创建代码生成不同类型和形式的对象. 当你希望使用 ...
- Python 中的设计模式详解之:策略模式
虽然设计模式与语言无关,但这并不意味着每一个模式都能在每一门语言中使用.<设计模式:可复用面向对象软件的基础>一书中有 23 个模式,其中有 16 个在动态语言中“不见了,或者简化了”. ...
- [ 转载 ] Java开发中的23种设计模式详解(转)
Java开发中的23种设计模式详解(转) 设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类 ...
- iOS中MVC等设计模式详解
iOS中MVC等设计模式详解 在iOS编程,利用设计模式可以大大提高你的开发效率,虽然在编写代码之初你需要花费较大时间把各种业务逻辑封装起来.(事实证明这是值得的!) 模型-视图-控制器(MVC)设计 ...
- 16个PHP设计模式详解
说明:该教程全部截选自实验楼教程[16个PHP设计模式详解]:主要介绍16个常用的设计模式的基础概念和技术要点,通过UML类图帮助理解设计模式中各个类之间的关联关系,针对每种设计模式都使用PHP完成了 ...
- android java 设计模式详解 Demo
android java 设计模式详解 最近看了一篇设计模式的文章,深得体会,在此基础我将每种设计模式的案例都写成Demo的形式,方便读者研究学习, 首先先将文章分享给大家: 设计模式(Design ...
- Java温故而知新(5)设计模式详解(23种)
一.设计模式的理解 刚开始“不懂”为什么要把很简单的东西搞得那么复杂.后来随着软件开发经验的增加才开始明白我所看到的“复杂”恰恰就是设计模式的精髓所在,我所理解的“简单”就是一把钥匙开一把锁的模式,目 ...
- JAVA设计模式简介及六种常见设计模式详解
一.什么是设计模式 ...
- Javascript设计模式详解
Javascript常用的设计模式详解 阅读目录 一:理解工厂模式 二:理解单体模式 三:理解模块模式 四:理解代理模式 五:理解职责链模式 六:命令模式的理解: 七:模板方法模式 八:理解javas ...
- javascript设计模式详解之命令模式
每种设计模式的出现都是为了弥补语言在某方面的不足,解决特定环境下的问题.思想是相通的.只不过不同的设计语言有其特定的实现.对javascript这种动态语言来说,弱类型的特性,与生俱来的多态性,导致某 ...
随机推荐
- 用字符串表达式执行引擎消除掉if else if
背景 最近我搞了个微信机器人,@机器人 xxx 这样来发送命令 能拿到的信息有,消息内容,消息发送人,消息所在的群id等 需要根据消息内容或者消息发送群id等不同的条件组合来决定走哪个处理逻辑. 简单 ...
- Go 匿名返回值的坑——这道题据说 90% 的同学都答错了!
今天分享的内容比较基础,准确地说是 Go 的语言特性--命名.匿名返回值. 先看下面的例子,猜测会输出什么? package main func main() { println(A()) print ...
- 模拟ArrayList(顺序表)的底层实现
模拟ArrayLIst的底层实现 package com.tedu.api04.list; import java.util.Objects; /** * @author LIGENSEN * Dat ...
- 【技术积累】Vue中的核心概念【四】
Vue的生命周期 Vue中的生命周期是指组件从创建到销毁的整个过程中,会触发一系列的钩子函数 Vue2中的生命周期 Vue2中的生命周期钩子函数是在组件的不同阶段执行的特定函数.这些钩子函数允许开发者 ...
- 堆 Heap & 栈 Stack(.Net)【概念解析系列_3】【C# 基础】
〇.前言 本文主要围绕 .Net 框架中的托管堆(Heap,简称堆)和堆栈(Stack,简称栈)展开. .Net 程序在 CLR(Common Language Runtime 公共语言运行时)上运行 ...
- asp.net core之HttpClient
本文介绍了ASP.NET Core中的HttpClient和HttpClientFactory的作用.用法以及最佳实践.通过示例代码的展示,读者可以了解如何使用HttpClient发送HTTP请求并处 ...
- wget 命令的使用:HTTP文件下载、FTP文件下载--九五小庞
1. wget 命令简介与安装wget是用于在命令行终端下载网络文件的开源免费的命令工具,支持 HTTP/HTTPS.FTP/FTPS 协议的下载.wget 与 curl 相似,curl 可以理解为是 ...
- 小白弄明白了 unix 时间戳的转换问题
小白对于将 unix 时间戳转换为日期时间和使用日期时间转换为 unix 时间戳,在项目中见到过很多,每次使用时不是用现有的方法转换就是网上搜索方法. 小白见过各种转换方式觉得moment库很是方便, ...
- 为什么 Python 代码在函数中运行得更快?
哈喽大家好,我是咸鱼 当谈到编程效率和性能优化时,Python 常常被调侃为"慢如蜗牛" 有趣的是,Python 代码在函数中运行往往比在全局范围内运行要快得多 小伙伴们可能会有这 ...
- HashMap底层源码分析
HashMap底层原理实现 1.HashMap初始化 jdk1.8版本之后:数组+链表+红黑树实现,先去观看HashMap的构造方法: 构造方法: public HashMap() { this.lo ...