引言
在软件系统中,有时需要创建一个复杂对象,并且这个复杂对象由其各部分子对象通过一定的步骤聚合而成。例如一个采购系统中,如果需要采购员去采购一批电脑,在这个实际需求中,电脑就是一个复杂的对象,它是由CPU、主板、硬盘、显卡、机箱等组装而成的,如果此时让采购员一台一台电脑去组装的话真是要累死他了。这里就可以用建造者模式来解决这个问题。我们可以把电脑的各个组件的组装过过场封装到一个建造者对象里,此时采购员不可能自己去买各个组件并把它们组织起来,此时采购员只需要向电脑城的老板说自己要采购什么样的电脑就可以了,电脑城老板自然会把组装好的电脑送到公司。下面用详细例子来说明。
具体实现
在这个例子中,电脑城的老板是直接与客户联系的,然而电脑的组装是由老板指挥装机人员去把电脑的各个部件组装起来,真正负责创建产品的人就是电脑城的装机人员。弄清了逻辑就用代码来实现逻辑:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
/// <summary>
/// 以组装电脑为例子
/// 每台电脑的组装过程是一致的,但是使用同样的的构建过程可以创建不同的表示(组装不一样的电脑)
/// 组装电脑的这个场景就可以应用建造者模式来设计
/// </summary>
namespace _20BuilderPatternDemo
{
/// <summary>
/// 客户类
/// </summary>
class Program
{
static void Main(string[] args)
{
//创建指挥者和构造者
Director director = new Director();
Builder b1 = new ConcreteBuilderOne();
Builder b2 = new ConcreteBuilderTwo();
//指挥者指定构造者b1去组装第一台电脑
director.Construct(b1);
//第一台电脑装好了
Computer computer = b1.GetComputer();
computer.show();
// 老板叫员工b2去组装第二台电脑
director.Construct(b2);
Computer computer2 = b2.GetComputer();
computer2.show();
}
}
/// <summary>
/// 指挥者指定一个人去组装电脑
/// 创建指挥者类
/// </summary>
public class Director
{
//组装电脑
public void Construct(Builder builder)
{
builder.BuildPartCPU();
builder.BuildPartMainBoard();
}
}
/// <summary>
/// 电脑类
/// </summary>
public class Computer
{
//电脑组件集合
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
{
//装CPU
public abstract void BuildPartCPU();
//装主板
public abstract void BuildPartMainBoard();
//还有其他部件主要组装,在此省略
//获得组装好的电脑
public abstract Computer GetComputer();
}
/// <summary>
/// 具体创建者(组装电脑的人)
/// </summary>
public class ConcreteBuilderOne : Builder
{
Computer computer = new Computer();
public override void BuildPartCPU()
{
computer.Add("CPU1");
}
public override void BuildPartMainBoard()
{
computer.Add("Main board1");
}
public override Computer GetComputer()
{
return computer;
}
}
public class ConcreteBuilderTwo : Builder
{
Computer computer = new Computer();
public override void BuildPartCPU()
{
computer.Add("CPU2");
}
public override void BuildPartMainBoard()
{
computer.Add("Main board2");
}
public override Computer GetComputer()
{
return computer;
}
}
}
/*output:
电脑开始组装—————————————————————
组件CPU1装好了
组件Main board1装好了
电脑装好了
电脑开始组装—————————————————————
组件CPU2装好了
组件Main board2装好了
电脑装好了
*/
定义
建造者模式:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
建造者模式使得建造代码和表示代码分离,可以使客户端不必知道产品内部组成的细节,从而降低了客户端与具体产品之间的耦合度。
类图:
建造者模式实现要点
- 在建造者模式中,指挥者是直接与客户端打交道的,指挥者将客户端创建产品的请求划分为对各个部件的创建请求,再将这些请求委派到具体的建造者角色,具体建造者角色是完成具体产品的构建工作的,不被客户端知道。
- 建造者模式主要用于“分步骤来构建一个复杂的对象”,其中“分步骤”是一个固定的组合过程,而复杂对象的各个部分是经常变化的(也就是说电脑的内部组件是经常变化的,这里指的变化是指硬盘的大小变了)
- 产品不需要抽象类,由于构造者模式创建出来的最终产品可能差异很大,所以不大可能提炼出一个抽象产品类。
- 建造者模式解决的是“产品部分”的需要变化。
- 由于创建者模式隐藏了具体产品的创建过程,所以要改变一个产品的内部表示,只需要在创建一个具体的创建者就可以了,从而能很好的应对产品组成组件的需求变化。
总结
建造者模式,将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。建造者模式的本质是使用组装过程(用指挥者类进行封装,从而达到解耦的目的)和创建具体产品解耦,使我们不用去关心每个组件是如何创建的。