创建型模式——生成器(Builder)
问题背景
当创建一个可以明显划分为多个可配置部件的复杂对象时,可以考虑使用生成器。比如我们现在要创建一台电脑,电脑有处理器、显卡和硬盘三个可配置部件。创建一台高配电脑和一台低配电脑,如果不使用生成器,代码是这样的:
var high = new Computer();
high.Cpu = new CoreI9();
high.Gpu = new TitanRTX();
high.Drive = new SSD();
var low = new Computer();
low.Cpu = new CoreI3();
low.Gpu = new GTX960();
low.Drive = new HHD();
这样做的弊端很明显:
- 用户必须清楚电脑创建过程中的每个细节,不利于程序的模块化。
- 用户必须手写大量创建代码,增加了出错率。
- 创建逻辑散落在程序的各个角落,会导致牵一发而动全身,不利于后期维护。
解决方案
为了隐藏复杂的创建逻辑,我们将电脑的创建封装到一个专门负责创建对象的类中,只暴露获取复杂对象的接口,改进后的程序结构是这样的:
使用生成器后,用户创建电脑时只需要创建对应的生成器实现,不再需要知道任何创建电脑的细节。同时,使用了稳定性较强的接口后也不容易出现牵一发而动全身的情况。
效果
- 将对象的创建和表示分离,降低了模块间的耦合度。
- 利用多态实现不同部件的组装,可扩展性强。
- 将创建逻辑提取到一处,防止逻辑分散。
缺陷
生成器的实现虽然可以通过多态进行扩展,但每多一种配置,哪怕只变了一个配置项,就需要一个新的生成器类,这在大型系统中会造成类爆炸。
相关模式
- 抽象工厂:生成器和抽象工厂都用来创建复杂对象,但关注点不同:生成器的关注点是整体,抽象工厂的关注点是部件。
- 复合:复合结构通常用生成器创建。
- 单例:生成器常被设计成单例类。
实现
using System;
namespace Builder
{
class Client
{
public interface ICPU { }
public interface IGPU { }
public interface IDrive { }
public class CoreI9 : ICPU
{
public override string ToString()
{
return "酷睿I9处理器";
}
}
public class CoreI3 : ICPU
{
public override string ToString()
{
return "酷睿I3处理器";
}
}
public class TitanRTX : IGPU
{
public override string ToString()
{
return "TitanRTX显卡";
}
}
public class GTX960 : IGPU
{
public override string ToString()
{
return "GTX960显卡";
}
}
public class SSD : IDrive
{
public override string ToString()
{
return "固态硬盘";
}
}
public class HHD : IDrive
{
public override string ToString()
{
return "机械硬盘";
}
}
public class Computer
{
public ICPU Cpu { get; set; }
public IGPU Gpu { get; set; }
public IDrive Drive { get; set; }
public override string ToString()
{
return $"一台{Cpu.ToString()},{Gpu.ToString()},{Drive.ToString()}的电脑";
}
}
public interface IComputerBuilder
{
Computer CreateComputer();
}
public class HighBuilder : IComputerBuilder
{
public Computer CreateComputer()
{
var computer = new Computer();
computer.Cpu = BuildCPU();
computer.Gpu = BuildGPU();
computer.Drive = BuildDrive();
return computer;
}
private ICPU BuildCPU()
{
return new CoreI9();
}
private IGPU BuildGPU()
{
return new TitanRTX();
}
private IDrive BuildDrive()
{
return new SSD();
}
}
public class LowBuilder : IComputerBuilder
{
public Computer CreateComputer()
{
var computer = new Computer();
computer.Cpu = BuildCPU();
computer.Gpu = BuildGPU();
computer.Drive = BuildDrive();
return computer;
}
private ICPU BuildCPU()
{
return new CoreI3();
}
private IGPU BuildGPU()
{
return new GTX960();
}
private IDrive BuildDrive()
{
return new HHD();
}
}
static void Main(string[] args)
{
Console.WriteLine("创建高配电脑...");
IComputerBuilder builder = new HighBuilder();
var high = builder.CreateComputer();
Console.WriteLine(high);
Console.WriteLine("创建低配电脑...");
builder = new LowBuilder();
var low = builder.CreateComputer();
Console.WriteLine(low);
}
}
}