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这种动态语言来说,弱类型的特性,与生俱来的多态性,导致某 ...
随机推荐
- Git无法push提示报错443
更新 设置代理不能完美解决问题,需要检查本地的SSH配置是否正确,以及正确配置SSH密钥关联github账户 配置SSH参考链接: <GitHub如何配置SSH Key> https:// ...
- 3D降噪_运动估计块运动匹配
运动估计 运动估计是视频去噪技术的重要组成之一,计算相邻两帧视频序列各像素的相对运动偏移量,从而得到其运动轨迹. 点 ( i , j ) (i,j) (i,j)和 ( x , y ) (x,y) (x ...
- ObjectInputStream_报错问题
报错: Exception in thread "main" java.io.StreamCorruptedException: invalid stream header: CE ...
- Cilium 系列-3-Cilium 的基本组件和重要概念
系列文章 Cilium 系列文章 前言 安装完了,我们看看 Cilium 有哪些组件和重要概念. Cilium 组件 如上所述,安装 Cilium 时,会安装几个运行组件(有些是可选组件), 它们各是 ...
- OOP第三次大作业
前言 前言的前言 快期末,也一直在等这次作业发布,我现在只能说终于等到了!!!跟上一个Blog的时间相隔比较大,内容也比较多,涉及范围也比较广7-11次小练习,废话不多说,直接开始吧.如果对我blog ...
- grafana 容器无法启动,打印权限问题
报错日志 open /var/lib/grafana/alerting/1/notifications: permission denied 问题原因 sudo chown -R docker: /v ...
- 洛谷 P1387 最大正方形 题解
方法1 二分+暴力+前缀和Check 注意细节 通过二维前缀和判定矩形内是否全为1,计算和等于长度的平方就判断为是 复杂度\(\Theta (n^2\log{n})\) #include <bi ...
- Spring Secriuty登录失败错误状态999重定向302
原因是login.html登录页面有不能加载的静态资源,找出来去掉就好了,比如 bootstrap.min.css 环境 使用Spring Boot Security 3做一个登录功能,使用了一个教程 ...
- 使用canvas(2d)+js实现一个简单的傅里叶级数绘制方波图
先看效果 查看页面右下角,嘿嘿 简要说明 创建具有不同半径与角速度的圆集合:(截图中展现的效果为5个,代码是30个,运行后效果会不同) const getCircles = (N = 10) => ...
- DORA指标:公司业务成果的“占卜师”
2009 年,受 John Allspaw 和 Paul Hammonds 在 Velocity 上演讲的启发,Patrick Debois 组织了一次名为"DevOps Days" ...