建造者模式(Builder)——从组装电脑开始
建造者模式(Builder)——从组装电脑开始
建造者模式概括起来就是将不同独立的组件按照一定的条件组合起来构成一个相对业务完整的对象。调用者无需知道构造的过程。
我们从组装电脑开始
让我们从买组装电脑开始吧。
首先要买一个电脑,一般都有两个选择 —— 品牌电脑和组装电脑,一般人为了省事和放心都会选择买品牌电脑(也就是整机)。在这里,为了更好的分析问题,假定我们为了性价比决定要买组装电脑。那么我们该怎么做呢。
首先我们得学习一个完整的电脑的组成部分有哪些?
经过翻查一部分资料发现,主要部件分为主板、CPU、显卡、显示屏、内存条等。这还刚开始,我们光知道这个还不行,每个硬件的品牌少说都有好几种,我们肯定希望在价格允许的情况选最好的。所以我们还得花时间找资料了解每个部件对应的品牌的口碑与使用者的实际体验情况(比如淘宝的卖家秀,以及网上一些专业的测评人的报告等)。
好了,研究完这个之后呢,总算是可以决定怎么搭配各种硬件了。但是最后又有一个问题来了,这些硬件买回来了,我们这些小白不会装啊,都不知道主机箱里每个部件对应的位置是哪里,以及怎么装上去。万一装坏了怎么办,那钱岂不是白花了。
又是一番曲折之后,总算是把整个电脑组装完毕了。就在我们举杯同庆的时候,突然发现了一个严重的问题……
“天呐,还开不了机啊,还要给电脑装系统啊”
“啊!!!那怎么办啊,都忙活一整天了。”
“还能怎么办啊?买都买了,装都装好了,只能装系统呀”
“也是,可我不会装系统啊,你会么?”
“……嗯~我也不会”
“哎,咱们还是去查资料怎么装系统吧”
上面的故事虽然在我们ITer来看,显得很搞笑和夸张。但是对于电脑小白来说,这可是绝对会发生的。因为在大学,我就是这么过来的。光怎么重装系统都花了我一天时间。
但是,别急,我们隔壁寝室的一个同学他早上说他也要买组装电脑。我们现在去看他怎么弄的吧,说实话,我既希望他也跟我们一样经过种种折磨,但是又希望他也能一帆风顺,这样就能教我们怎么装系统了啊。
什么?已经开始玩电脑了
当我们进寝室门的时候,令我们目瞪口呆的事情发生了,我发现他已经开始玩英雄联盟了,都已经三杀并成功结束游戏。
我马上就问他怎么这么快就玩上电脑了,然后我就把我一整天的遭遇发泄了出来。只见他哈哈大笑
”现在谁还自己买各种部件来装电脑啊,更何况像你们还不懂这些。“
”那不然怎么弄,品牌机同等价位的比组装机要贵好多啊“
”哈哈,你这个蠢嘛批,你可以去电脑城让老板帮你组装不就行了,你只需要为此付一些手工费就行了嘛,也不贵啊“
”……“
开始对号入座
第一则故事其实就相当于我们没有用建造者模式开发可能面临的一些问题。为了生成一个业务对象(组装电脑),我们得花很多时间精力来收集业务对象的成员信息(组成部分)。这么多对象全由我一个人(客户端)组织,这样就会强耦合,并很有可能因为一些细小需求的改变而导致整个功能异常(忘记装系统,内存条型号不对等)。从而浪费了更多的时间和精力,增加了我们的劳动成本和经济成本。
第二则故事就完全不同,我(用户/客户端)完全不需关心业务对象的构建过程,只需要找电脑城老板(构建者)要对象就行了。
首先有一个前提,就是有一个规则依据(契约)来构造一个正确的业务对象(电脑)。
所以为了以正确姿势来组装电脑,我们定义了一些必要的成员(硬件)
public interface IFullComputer {
string Mainboard { get; }
string CPU { get; }
string Disk { get; }
string Graphics { get; }
string Display { get; }
bool HasOperatingSystem { get; }
}
有了它才代表一个完整正确的电脑,我们先来看我们第二个故事是怎么实现结果调用的吧。
public class Client {
// 交给电脑城老板
private void IWantBuyComputer() {
// 见到老板
var boss = new ComputerCityBoss();
// 告诉老板我想要什么配置的电脑,这里简单起就用老板推荐的
var computerBuilder = new DefaultFullComputerBuilder();
var computer = boss.TellMeThenReturnComputer(computerBuilder);
Console.WriteLine("电脑组件完毕,是否预装系统:" + computer.HasOperatingSystem);
}
}
客户端(用户)已经很简单了,就跟我们现在很多人买电脑一样,去电脑城把自己搭配的电脑配置给老板,然后就等着老板把组装好的电脑交给你。你根本不需要知道电脑组装的细节。这样从代码上就能做客户端与业务数据分离。
现在我们来看具体实现代码。
public interface IFullComputerBuilder : IFullComputer {
IFullComputer Create();
}
public class DefaultFullComputerBuilder : AbstractFullComputerBuilder {
protected override void SetCPU() {
}
protected override void SetDisk() {
}
protected override void SetDisplay() {
}
protected override void SetGraphics() {
}
protected override void SetMainboard() {
}
}
// 老板与品牌商有合作
public abstract class AbstractFullComputerBuilder : IFullComputerBuilder {
public string Mainboard { get; set; } = "默认品牌主板";
public string CPU { get; set; } = "默认品牌CPU";
public string Disk { get; set; } = "默认品牌内存";
public string Graphics { get; set; } = "默认品牌显卡";
public string Display { get; set; } = "默认品牌显示器";
public bool HasOperatingSystem { get; set; }
public IFullComputer Create() {
SetMainboard();
SetCPU();
SetDisk();
SetDisplay();
SetGraphics();
InstallOperatingSystem();
if (!HasOperatingSystem) throw new InvalidOperationException("install faild: no operating system");
return this;
}
protected abstract void SetMainboard();
protected abstract void SetCPU();
protected abstract void SetDisk();
protected abstract void SetGraphics();
protected abstract void SetDisplay();
private void InstallOperatingSystem() {
//if (!condition) return;
HasOperatingSystem = true;
}
}
老板就会根据你的要求来给你组装电脑。当然,如果你没有特殊要求,那老板就会默认用品牌合作商的,利润更多嘛。
public class ComputerCityBoss {
public IFullComputer TellMeThenReturnComputer(IFullComputerBuilder builder) {
return builder.Create();
}
}
再来看.NETCore源码加深学习
我们在可以通过一些优秀的框架的源码来学习加深我们对知识点的理解。
在 .netcore 中,Builder 模式是很常见的。相信很多人都知道 .netcore 启动程序就是用 Builder 模式:
public class Program {
public static void Main(string[] args) {
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder => {
webBuilder.UseStartup<Startup>();
});
}
其中 IHostBuilder 就是一个构造者。我们来看默认实现者 HostBuilder 的源代码:
public IHost Build()
{
if (_hostBuilt)
{
throw new InvalidOperationException("Build can only be called once.");
}
_hostBuilt = true;
BuildHostConfiguration();
CreateHostingEnvironment();
CreateHostBuilderContext();
BuildAppConfiguration();
CreateServiceProvider();
return _appServices.GetRequiredService<IHost>();
}
很明显,它所做的就跟我们之前讲的例子 —— AbstractFullComputerBuilder 做的是一样的。都了为了构成一个完整的对象,内部组织了很多的模块。而外部客户端(Program)根本不需要知道其内部的具体细节,只负责调用 Builder 即可。
建造者模式(Builder)——从组装电脑开始的更多相关文章
- 设计模式系列之建造者模式(Builder Pattern)——复杂对象的组装与创建
说明:设计模式系列文章是读刘伟所著<设计模式的艺术之道(软件开发人员内功修炼之道)>一书的阅读笔记.个人感觉这本书讲的不错,有兴趣推荐读一读.详细内容也可以看看此书作者的博客https:/ ...
- 建造者模式(Builder)-宏观的使用角度
建造者模式(Builder) 建造者模式是用来解决产品对象的创建过程是由多个零件组成的情况,这些零件与产品本身是组合关系,也就是部分与整体,这些零件的创建顺序,还有一些创建中的逻辑,都是稳定的,可以封 ...
- 【原】iOS设计模式之:建造者模式Builder Pattern,用于改进初始化参数
本文主要讨论一下iOS中的Builder Pattern.与网上很多版本不同,本文不去长篇大论地解释建造者模式的概念,那些东西太虚了.设计模式这种东西是为了解决实际问题的,不能为了设计模式而设计模式, ...
- 乐在其中设计模式(C#) - 建造者模式(Builder Pattern)
原文:乐在其中设计模式(C#) - 建造者模式(Builder Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 建造者模式(Builder Pattern) 作者:webabc ...
- 【设计模式】建造者模式 Builder Pattern
前面学习了简单工厂模式,工厂方法模式以及抽象工厂模式,这些都是创建类的对象所使用的一些常用的方法和套路, 那么如果我们创建一个很复杂的对象可上面的三种方法都不太适合,那么“专业的事交给专业人去做”,2 ...
- 建造者模式(Builder Pattern)
建造者模式(Builder Pattern) 它可以将多个简单的对象一步一步构建成一个复杂的对象. 意图:将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示. 主要解决:主要解决在软 ...
- 二十四种设计模式:建造者模式(Builder Pattern)
建造者模式(Builder Pattern) 介绍将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示. 示例用同样的构建过程创建Sql和Xml的Insert()方法和Get()方 ...
- iOS设计模式之:建造者模式Builder Pattern,用于改进初始化参数
转自:http://www.cnblogs.com/wengzilin/p/4365855.html 本文主要讨论一下iOS中的Builder Pattern.与网上很多版本不同,本文不去长篇大论地解 ...
- 设计模式—建造者模式(Builder)
title: 设计模式-建造者模式 建造者模式(Builder)是一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就可以构建它们,用户不需要知道内部的具体构建细节.建造者模式属于对 ...
随机推荐
- 3万字总结,Mysql优化之精髓
本文知识点较多,篇幅较长,请耐心学习 MySQL已经成为时下关系型数据库产品的中坚力量,备受互联网大厂的青睐,出门面试想进BAT,想拿高工资,不会点MySQL优化知识,拿offer的成功率会大大下降. ...
- 基于Arduino开发的智能蓝牙小车
基于Arduino的智能蓝牙小车 材料准备: Arduino开发板一块.四驱小车底板及相关配件一套.L298N驱动模块一个.HC-05/06蓝牙模块一块,九伏电源一块(用于主板供电).12V锂电池一块 ...
- 使用 FRP 让部门同事都能直接远程桌面办公( 适用于 TEAM 和向日葵卡顿的用户)
背景说明 这两天由于疫情的原因,很多公司都得在家远程上班,然后像我们这类小公司有没有 VPN 这些东西.传统的远程回公司只能依靠 Teamviewer 或者向日葵等工具.但是由于最近用户量很多,可能会 ...
- LUA学习笔记(第5-6章)
x = a or b 如果a为真则x = a 如果a为假则x = b print(a .. b) 任何非nil类型都会被连接为字符串,输出 多重返回值 local s,e = string.find( ...
- LeetCode.509——斐波那契数
问题描述: 斐波那契数,通常用 F(n) 表示,形成的序列称为斐波那契数列.该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和.也就是: F(0) = 0, F(1) = 1 F(N) ...
- 使用IntelliJ IDEA创建Maven工程
1. 新建项目(点击“+ Create New Project”): 2. 选择Maven,不必选择项目骨架,直接点击Next 按钮即可: 3. 输入项目名称,选择项目位置,输入组织名称,模块名称,项 ...
- [pathlib]内置pathlib库的常用属性和方法
pathlib中的Path类可以创建path路径对象, 属于比os.path更高抽象级别的对象. 官网 from pathlib import Path path = Path(__file__) p ...
- Altium Designer打印多块PCB到热转印纸上、拼板发给工厂
接下来介绍的方法的优势有: 节省电脑性能(来自不同PCB文件的图案被放置时只在第1块会卡顿一小会儿,之后不再卡顿) 便于排版(拖放图案时绝不会改变图案内容,拖放图案时鼠标拖住的矩形框的尺寸与图案的尺寸 ...
- python练习——第3题
原GitHub地址:https://github.com/Yixiaohan/show-me-the-code 题目:将 0001 题生成的 200 个激活码(或者优惠券)保存到 Redis 非关系型 ...
- Go语言实现:【剑指offer】滑动窗口的最大值
该题目来源于牛客网<剑指offer>专题. 给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值.例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存 ...