模式开发之旅(8):建造者模式
2010-07-03 19:56:08建造者模式: 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
建造者模式的原理和实现比较简单,重点是掌握应用场景,避免过度使用。
如果一个类中有很多属性,为了避免构造函数的参数列表过长,影响代码的可读性和易用性,我们可以通过构造函数配合 set() 方法来解决。但是,如果存在下面情况中的任意一种,我们就要考虑使用建造者模式了。
- 我们把类的必填属性放到构造函数中,强制创建对象的时候就设置。如果必填的属性有很多,把这些必填属性都放到构造函数中设置,那构造函数就又会出现参数列表很长的问题。如果我们把必填属性通过 set() 方法设置,那校验这些必填属性是否已经填写的逻辑就无处安放了。
- 如果类的属性之间有一定的依赖关系或者约束条件,我们继续使用构造函数配合 set() 方法的设计思路,那这些依赖关系或约束条件的校验逻辑就无处安放了。
- 如果我们希望创建不可变对象,也就是说,对象在创建好之后,就不能再修改内部的属性值,要实现这个功能,我们就不能在类中暴露 set() 方法。构造函数配合 set() 方法来设置属性值的方式就不适用了。
下面代码是一个组装小型汽车的实例,小汽车包括的核心配件基本一样,都有引擎、轮胎、车灯等,但不同的工厂工人组装小汽车的工作流程都不同。我们可以使用建造者模式封装不同工人对象创建的细节。
/// <summary>
/// 工人抽象
/// </summary>
public abstract class AbstractBuilder
{
public abstract void Engine();
public abstract void Wheels();
public abstract void Light();
public abstract Car Car();
}
/// <summary>
/// 比亚迪工人
/// </summary>
public class BuilderBYD : AbstractBuilder
{
private Engine _Engine = null;
private Wheels _Wheels = null;
private Light _Light = null;
public override void Engine()
{
this._Engine = new Engine()
{
Name = "_Engine"
};
Console.WriteLine("{0} build Engine", this.GetType().Name);
}
public override void Wheels()
{
this._Wheels = new Wheels()
{
Name = "_Wheels"
};
Console.WriteLine("{0} build Wheels", this.GetType().Name);
}
public override void Light()
{
this._Light = new Light()
{
Name = "_Light"
};
Console.WriteLine("{0} build Light", this.GetType().Name);
}
public override Car Car()
{
Console.WriteLine("组装 {0} {1} {2}", this._Engine, this._Light, this._Wheels);
Console.WriteLine("{0} build 比亚迪*唐", this.GetType().Name);
return new Car(this._Engine, this._Light, this._Wheels)
{
Name = "比亚迪*唐"
};
}
}
与工厂模式有何区别
工厂模式是用来创建不同但是相关类型的对象(继承同一父类或者接口的一组子类),由给定的参数来决定创建哪种类型的对象。建造者模式是用来创建一种类型的复杂对象,通过设置不同的可选参数,“定制化”地创建不同的对象。
网上有一个经典的例子很好地解释了两者的区别。
顾客走进一家餐馆点餐,我们利用工厂模式,根据用户不同的选择,来制作不同的食物,比如披萨、汉堡、沙拉。对于披萨来说,用户又有各种配料可以定制,比如奶酪、西红柿、起司,我们通过建造者模式根据用户选择的不同配料来制作披萨。