在五大设计原则的基础上经过GOF(四人组)的总结,得出了23种经典设计模式,其中分为三大类:创建型(5种)、结构型(7种)、行为型(11种)。今天对创建型中的构建者(Builder)模式的思想进行了一下复习和实践,在此做一下记录。理解或实践不到位的地方,希望走过路过的看官指正一下!
先来看看构建者(Builder)模式的定义:
Separate the construction of a complex object from its representation,so that the same construction process can create different representations.
意思就是说:将复杂对象的构造与其表示分离,以便相同的构造过程可以创建不同的表示。
也就是当一个对象比较复杂,而且每次的构造过程又相同的时候,可以考虑一下使用构建者模式。今天重新复习该模式的思想后,中午出去吃饭刚好接到“阿尔法.罗密欧”的汽车销售广告,背后有Giulia的配置表。咋一看这汽车整车构造:尺寸和重量、发动机、轮圈和底盘、安全技术....一大堆的部件和参数,确实够复杂的哈,再想想汽车的生产和组装过程几乎也可以说是相同的。以汽车和其生产组装过程作为实践构建者(Builder)模式的例子应该比较能说清楚!那就撸起袖子码起来,为是简单起见我把汽车和相关部件定义的比较粗陋,构建过程也很简陋,但应该能很好的说明构建者(Builder)模式的应用场景和原理了!
先将复杂对象——汽车(Car)的主要部件(底盘、发动机、变速箱、轮胎、车身)定义一下:
/// <summary>
/// 底盘
/// </summary>
[Serializable]
public class Chassis
{
/// <summary>
/// 轴距(前后轮之车轮轴距离)
/// </summary>
public int Wheelbase { get; set; }
/// <summary>
/// 驱动方式<see cref="DriveMode"/>
/// </summary>
public DriveMode DriveMode { get; set; } /// <summary>
/// 初始化底盘
/// </summary>
public Chassis() { } /// <summary>
/// 初始化底盘(带参)
/// </summary>
/// <param name="wheelbase">轴距(前后轮之车轮轴距离)</param>
/// <param name="driveMode">驱动方式<see cref="DriveMode"/></param>
public Chassis(int wheelbase, DriveMode driveMode)
{
Wheelbase = wheelbase;
DriveMode = driveMode;
} /// <summary>
/// 格式化输出底盘信息
/// </summary>
/// <returns>底盘信息</returns>
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.AppendLine(string.Format("轴距(mm):{0}", Wheelbase));
sb.AppendLine(string.Format("驱动方式:{0}", Enum.GetName(typeof(DriveMode), DriveMode)));
return sb.ToString();
}
} /// <summary>
/// 发动机接口
/// </summary>
public interface IEngine
{
/// <summary>
/// 喷油
/// </summary>
/// <param name="fuelQuantity">燃油量</param>
void FuelInjection(double fuelQuantity);
/// <summary>
/// 进(氧)气
/// </summary>
/// <param name="oxygenValue">氧气值</param>
void OxygenIntake(double oxygenValue);
/// <summary>
/// 点火启动
/// </summary>
/// <returns>是否动启成功</returns>
bool IgnitionStart();
/// <summary>
/// 做功并输出动力
/// </summary>
/// <returns>输出的动力值</returns>
double Work();
} /// <summary>
/// 发动机
/// </summary>
[Serializable]
public class Engine : IEngine
{
/// <summary>
/// 喷油量
/// </summary>
protected double fuelQuantity;
/// <summary>
/// 进(氧)气量
/// </summary>
protected double oxygenValue;
/// <summary>
/// 是否已启动
/// </summary>
protected bool isStarted = false;
/// <summary>
/// 汽缸数
/// </summary>
public int CylinderNumber { get; set; }
/// <summary>
/// 单缸气门数
/// </summary>
public int ValveNumber { get; set; }
/// <summary>
/// 总气门数
/// </summary>
public int TotalValveNumber
{
get
{
return CylinderNumber * ValveNumber;
}
}
/// <summary>
/// 冷却方式<see cref="CoolingMode"/>
/// </summary>
public CoolingMode CoolingMode { get; set; } /// <summary>
/// 初始化发动机
/// </summary>
public Engine() { } /// <summary>
/// 初始化发动机(带参)
/// </summary>
/// <param name="cylinderNumber">汽缸数</param>
/// <param name="valveNumber">单缸气门数</param>
/// <param name="coolingMode">冷却方式<see cref="CoolingMode"/></param>
public Engine(int cylinderNumber, int valveNumber, CoolingMode coolingMode)
{
CylinderNumber = cylinderNumber;
ValveNumber = valveNumber;
CoolingMode = coolingMode;
} /// <summary>
/// 格式化输出发动机信息
/// </summary>
/// <returns>发动机信息</returns>
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.AppendLine(string.Format("汽缸数量:{0}", CylinderNumber));
sb.AppendLine(string.Format("气门数量:{0}", TotalValveNumber));
sb.AppendLine(string.Format("冷却方式:{0}", Enum.GetName(typeof(CoolingMode), CoolingMode)));
return sb.ToString();
} /// <summary>
/// 喷油
/// </summary>
/// <param name="fuelQuantity">燃油量</param>
public virtual void FuelInjection(double fuelQuantity)
{
this.fuelQuantity = fuelQuantity;
} /// <summary>
/// 进(氧)气
/// </summary>
/// <param name="oxygenValue">氧气值</param>
public virtual void OxygenIntake(double oxygenValue)
{
this.oxygenValue = oxygenValue;
} /// <summary>
/// 点火启动
/// </summary>
/// <returns>是否动启成功</returns>
public virtual bool IgnitionStart()
{
if (fuelQuantity <= )
{
isStarted = false;
throw new Exception("发动机点火失败,燃油不足或喷油系统故障!");
}
if (oxygenValue <= )
{
isStarted = false;
throw new Exception("发动机点火失败,气门关闭或气门系统故障!");
}
isStarted = true;
Console.WriteLine("启动成功,发动机正常工作!");
return isStarted;
} /// <summary>
/// 做功并输出动力
/// </summary>
/// <returns>输出的动力值</returns>
public virtual double Work()
{
if (isStarted)
{
if (fuelQuantity <= )
{
isStarted = false;
throw new Exception("发动机熄火,燃油不足或喷油系统故障!");
}
if (oxygenValue <= )
{
isStarted = false;
throw new Exception("发动机熄火,气门关闭或气门系统故障!");
}
//这里只做简单的假设性能量转换
if (CoolingMode.Equals(CoolingMode.WaterCooling))
{
return fuelQuantity * oxygenValue * CylinderNumber * TotalValveNumber * 0.85;
}
else
{
return fuelQuantity * oxygenValue * CylinderNumber * TotalValveNumber * 0.75;
}
}
else
{
Console.WriteLine("发动机未启动!");
return ;
}
}
} /// <summary>
/// 变速箱动力输出结构
/// </summary>
[Serializable]
public struct GearboxOutput
{
/// <summary>
/// 驱动轮转矩
/// </summary>
public double Torque;
/// <summary>
/// 转速
/// </summary>
public double Speed;
/// <summary>
/// 传动方向
/// </summary>
public TransmitDirection direction;
} /// <summary>
/// 变速箱接口
/// </summary>
public interface IGearBox
{
/// <summary>
/// 根据当前变速箱所挂档位、传动方向和所连接的发动机进行动力传输
/// </summary>
/// <param name="engine">连接的发动机</param>
/// <returns>动力传输结果</returns>
GearboxOutput TransmitPower(IEngine engine);
} /// <summary>
/// 变速箱
/// </summary>
[Serializable]
public class Gearbox : IGearBox
{
/// <summary>
/// 变速箱类型<see cref="GearboxType"/>
/// </summary>
public GearboxType GearboxType { get; set; }
/// <summary>
/// 当前档位(会影响动力传送)<see cref="GearPosition"/>
/// </summary>
public GearPosition CurrentPosition { get; set; }
/// <summary>
/// 传动方向<see cref="TransmitDirection"/>
/// </summary>
public TransmitDirection TransmitDirection { get; set; } /// <summary>
/// 初始化变速箱
/// </summary>
public Gearbox() { CurrentPosition = GearPosition.N; } /// <summary>
/// 初始化变速箱(带参)
/// </summary>
/// <param name="gearboxType">变速箱类型<see cref="GearboxType"/></param>
public Gearbox(GearboxType gearboxType)
{
GearboxType = gearboxType;
CurrentPosition = GearPosition.N;
} /// <summary>
/// 格式化输出变速箱信息
/// </summary>
/// <returns>变速箱信息</returns>
public override string ToString()
{
return string.Format("变速箱类型:{0}\r", Enum.GetName(typeof(GearboxType), GearboxType));
} /// <summary>
/// 根据当前变速箱所挂档位、传动方向和所连接的发动机进行动力传输
/// </summary>
/// <param name="engine">连接的发动机</param>
/// <returns>动力传输结果</returns>
public virtual GearboxOutput TransmitPower(IEngine engine)
{
//这里只做简单的假设性动力传输
int currentPositionValue = int.Parse(Convert.ToString(CurrentPosition));
double enginePower = engine.Work();
GearboxOutput gearboxOutput = new GearboxOutput();
gearboxOutput.Speed = enginePower * currentPositionValue;
gearboxOutput.Torque = - currentPositionValue;
gearboxOutput.direction = TransmitDirection;
return gearboxOutput;
}
} /// <summary>
/// 轮胎
/// </summary>
[Serializable]
public class Tyre
{
/// <summary>
/// 轮胎预装位置
/// </summary>
public TyrePosition TyrePosition { get; set; }
/// <summary>
/// 胎宽(mm)
/// </summary>
public int Width { get; set; }
/// <summary>
/// 胎厚(mm)<
/// </summary>
public int Thickness { get; set; }
/// <summary>
/// 轮辋直径(英寸)
/// </summary>
public double Radial { get; set; }
/// <summary>
/// 载重系数(一般不超过110)
/// </summary>
public int LoadIndex { get; set; }
/// <summary>
/// 速度等级<see cref="SpeedGrade"/>
/// </summary>
public SpeedGrade SpeedGrade { get; set; }
/// <summary>
/// 胎面花纹种类<see cref="TreadPattern"/>
/// </summary>
public TreadPattern TreadPattern { get; set; } /// <summary>
/// 初始化轮胎
/// </summary>
public Tyre() { } /// <summary>
/// 初始化轮胎(带参)
/// </summary>
/// <param name="width">胎宽(mm)</param>
/// <param name="thickness">胎厚(mm)</param>
/// <param name="radial">轮辋直径(英寸)</param>
/// <param name="loadIndex">载重系数(一般不超过110)</param>
/// <param name="speedGrade">速度等级<see cref="SpeedGrade"/></param>
/// <param name="treadPattern">胎面花纹种类<see cref="TreadPattern"/></param>
public Tyre(int width, int thickness, double radial, int loadIndex, SpeedGrade speedGrade, TreadPattern treadPattern)
{
Width = width;
Thickness = thickness;
Radial = radial;
LoadIndex = loadIndex;
SpeedGrade = speedGrade;
TreadPattern = treadPattern;
} /// <summary>
/// 初始化轮胎(带参并指明轮胎预装位置)
/// </summary>
/// <param name="width">胎宽(mm)</param>
/// <param name="thickness">胎厚(mm)</param>
/// <param name="radial">轮辋直径(英寸)</param>
/// <param name="loadIndex">载重系数(一般不超过110)</param>
/// <param name="speedGrade">速度等级<see cref="SpeedGrade"/></param>
/// <param name="treadPattern">胎面花纹种类<see cref="TreadPattern"/></param>
/// <param name="tyrePosition">轮胎位置</param>
public Tyre(int width, int thickness, double radial, int loadIndex, SpeedGrade speedGrade, TreadPattern treadPattern, TyrePosition tyrePosition)
{
Width = width;
Thickness = thickness;
Radial = radial;
LoadIndex = loadIndex;
SpeedGrade = speedGrade;
TreadPattern = treadPattern;
TyrePosition = tyrePosition;
} /// <summary>
/// 输出轮胎规格描述([胎宽mm]/[胎厚与胎宽的百分比] R[轮辋直径(英寸)] [载重系数][速度标识])
/// </summary>
/// <returns>轮胎规格描述</returns>
public override string ToString()
{
return string.Format("轮胎规格:{0}/{1} R{2} {3}{4}", Width, ((Thickness*) / Width), Radial, LoadIndex, Enum.GetName(typeof(SpeedGrade), SpeedGrade));
}
} /// <summary>
/// 车身
/// </summary>
[Serializable]
public class Bodywork
{
/// <summary>
/// 车身结构<see cref="BodyworkStructure"/>
/// </summary>
public BodyworkStructure Structure { get; set; }
/// <summary>
/// 车身颜色<see cref="BodyworkColor"/>
/// </summary>
public BodyworkColor Color { get; set; }
/// <summary>
/// 长(mm)
/// </summary>
public int Length { get; set; }
/// <summary>
/// 宽(mm)
/// </summary>
public int Width { get; set; }
/// <summary>
/// 高(mm)
/// </summary>
public int Height { get; set; } /// <summary>
/// 初始化车身
/// </summary>
public Bodywork() { } /// <summary>
/// 初始化车身(带参)
/// </summary>
/// <param name="structure">车身结构<see cref="BodyworkStructure"/></param>
/// <param name="color">车身颜色<see cref="BodyworkColor"/></param>
/// <param name="length">长(mm)</param>
/// <param name="width">宽(mm)</param>
/// <param name="height">高(mm)</param>
public Bodywork(BodyworkStructure structure, BodyworkColor color, int length, int width, int height)
{
Structure = structure;
Color = color;
Length = length;
Width = width;
Height = height;
} /// <summary>
/// 格式化输出车身信息
/// </summary>
/// <returns>车身信息</returns>
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.AppendLine(string.Format("车身结构:{0}", Enum.GetName(typeof(BodyworkStructure), Structure)));
sb.AppendLine(string.Format("车身颜色:{0}", Enum.GetName(typeof(BodyworkColor), Color)));
sb.AppendLine(string.Format("长度/宽度/高度(mm):{0}/{1}/{2}", Length, Width, Height));
return sb.ToString();
}
}
可以看到简陋的主要部件的定义都已经够复杂了,汽车整车不用说都符合a complex object这个标准!
以下是汽车(Car)及其相关主要部件(底盘、发动机、变速箱、轮胎、车身)定义中用到的枚举:
/// <summary>
/// 车辆驱动方式
/// </summary>
public enum DriveMode
{
/// <summary>
/// 前轮驱动
/// </summary>
FrontWheelDrive,
/// <summary>
/// 后轮驱动
/// </summary>
RearWheelDrive,
/// <summary>
/// 全时全轮驱动
/// </summary>
FullTimeAllWheelDrive,
/// <summary>
/// 接通式全轮驱动
/// </summary>
OnLineFullWheelDrive
} /// <summary>
/// 发动机冷却方式
/// </summary>
public enum CoolingMode
{
/// <summary>
/// 风冷
/// </summary>
AirCooling,
/// <summary>
/// 水冷
/// </summary>
WaterCooling
} /// <summary>
/// 变速箱类型
/// </summary>
public enum GearboxType
{
/// <summary>
/// 自动型
/// </summary>
Automatic,
/// <summary>
/// 手动型
/// </summary>
Manual
} /// <summary>
/// 自动档与手动档通用档位
/// </summary>
public enum GearPosition
{
First = ,
Second = ,
Third = ,
Fourth = ,
Fifth = ,
Sixth = ,
Seventh = ,
Eighth = ,
Ninth = ,
/// <summary>
/// 空档
/// </summary>
N =
} /// <summary>
/// 变速箱传动方向
/// </summary>
public enum TransmitDirection
{
/// <summary>
/// 正向(前进)
/// </summary>
Forward = ,
/// <summary>
/// 反向(后退)
/// </summary>
Backward = -
} /// <summary>
/// 轮胎速度等级,对应的枚举值为相应等级的最高时速(单位km/h)
/// </summary>
public enum SpeedGrade
{
A1 = ,
A2 = ,
A3 = ,
A4 = ,
A5 = ,
A6 = ,
A7 = ,
A8 = ,
B = ,
C = ,
D = ,
E = ,
F = ,
G = ,
J = ,
K = ,
L = ,
M = ,
N = ,
P = ,
Q = ,
R = ,
S = ,
T = ,
U = ,
H = ,
V = ,
W = ,
Y = ,
/// <summary>
/// 超过240km/h的通用等级
/// </summary>
ZR =
} /// <summary>
/// 胎面花纹
/// </summary>
public enum TreadPattern
{
/// <summary>
/// 无花纹(光头轮胎)
/// </summary>
None,
/// <summary>
/// 纵向花纹
/// </summary>
Longitudinal,
/// <summary>
/// 横向花纹
/// </summary>
Transverse,
/// <summary>
/// 单导向花纹
/// </summary>
SingleGuide,
/// <summary>
/// 块状花纹
/// </summary>
Lumpy,
/// <summary>
/// 不对称花纹
/// </summary>
Asymmetrical,
/// <summary>
/// 混合花纹
/// </summary>
Mixed
} /// <summary>
/// 轮胎位置
/// </summary>
public enum TyrePosition
{
/// <summary>
/// 前轮
/// </summary>
Front,
/// <summary>
/// 后轮
/// </summary>
Rear
} /// <summary>
/// 车身结构
/// </summary>
public enum BodyworkStructure
{
/// <summary>
/// 非承载式
/// </summary>
NonLoad,
/// <summary>
/// 承载式
/// </summary>
Load,
/// <summary>
/// 半承载式
/// </summary>
HalfLoad
} /// <summary>
/// 车身颜色
/// </summary>
public enum BodyworkColor
{
Black,
White,
Red,
Yellow,
Silvery,
Blue,
Gray
}
终于轮到汽车整车(Car)的定义了:
/// <summary>
/// 汽车
/// </summary>
public class Car
{
private readonly string name;
private readonly string model; /// <summary>
/// 车名
/// </summary>
public string Name { get { return this.name; } }
/// <summary>
/// 型号
/// </summary>
public string Model { get { return this.model; } }
/// <summary>
/// 底盘
/// </summary>
public Chassis Chassis { get; set; }
/// <summary>
/// 发动机
/// </summary>
public IEngine Engine { get; set; }
/// <summary>
/// 变速箱
/// </summary>
public IGearBox GearBox { get; set; }
/// <summary>
/// 轮胎
/// </summary>
public IList<Tyre> Tyres { get; set; }
/// <summary>
/// 车身
/// </summary>
public Bodywork Bodywork { get; set; } /// <summary>
/// 初始化汽车
/// </summary>
public Car() { } /// <summary>
/// 初始化汽车(带简要参数)
/// </summary>
/// <param name="name"></param>
/// <param name="model"></param>
public Car(string name, string model)
{
this.name = name;
this.model = model;
} /// <summary>
/// 格式化输出整车信息
/// </summary>
/// <returns>整车信息</returns>
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.AppendLine(string.Format("车名:{0}", this.name));
sb.AppendLine(string.Format("型号:{0}", this.model));
sb.AppendLine(Chassis.ToString());
sb.AppendLine(Engine.ToString());
sb.AppendLine(GearBox.ToString());
sb.AppendLine(Bodywork.ToString());
if (Tyres != null && Tyres.Count > )
{
var tyreGroups = Tyres.GroupBy(t => t.TyrePosition);
if (tyreGroups.Count() > )
{
foreach (var group in tyreGroups)
{
sb.AppendLine(string.Format("{0}{1}", Enum.GetName(typeof(TyrePosition), group.First().TyrePosition), group.First().ToString()));
} }
else
{
sb.AppendLine(Tyres[].ToString());
}
sb.AppendLine(string.Format("轮胎数量:{0}", Tyres.Count));
}
return sb.ToString();
}
}
汽车整车主要由底盘、发动机、变速箱、轮胎、车身等组装而成,但汽车类Car中并没有给出这些部件的生产和组装方法(过程),因为这些过程比较复杂,而且对于汽车生产来说都要经过这些标准过程(规范),我们将这些复杂的部件生产和组装过程交给专门的构建者去做——即将复杂对象的构造与其表示分离!
我们先定义一下汽车生产组装的主要过程标准——构建标准(规范):
/// <summary>
/// 汽车构建标准(规范)
/// </summary>
public interface IBuilder
{
/// <summary>
/// 构建底盘
/// </summary>
void BuildChassis(); /// <summary>
/// 构建发动机
/// </summary>
void BuildEngine(); /// <summary>
/// 构建变速箱
/// </summary>
void BuildGearbox(); /// <summary>
/// 构建轮胎
/// </summary>
void BuildTyre(); /// <summary>
/// 构建车身
/// </summary>
void BuildBodywork(); /// <summary>
/// 取得构建好的汽车
/// </summary>
/// <returns>构建好的汽车</returns>
Car GetCar();
}
有了要构建的产品——汽车Car,也有了构建标准(规范)——IBuilder接口,但具体执行各个部件构建的构建者还没有,这个很容易,只要让构建者按构建标准(规范)来实现各个部件的构建过程就行了——即实现IBuilder接口,例如宝马(BWM)和奔驰(Benz)的构建者对自己某个车型的构建实现:
/// <summary>
/// 宝马(BWM)构建者(对各个部件有自己的生产工艺)
/// </summary>
public class BwmBuilder : IBuilder
{
private Car bwmCar = new Car("BWM", "X7");
public void BuildBodywork()
{
Thread.Sleep();//模拟耗时
bwmCar.Bodywork = new Bodywork(BodyworkStructure.HalfLoad, BodyworkColor.Silvery, , , );
} public void BuildChassis()
{
Thread.Sleep();//模拟耗时
bwmCar.Chassis = new Chassis(, DriveMode.FullTimeAllWheelDrive);
} public void BuildEngine()
{
Thread.Sleep();//模拟耗时
bwmCar.Engine = new Engine(, , CoolingMode.WaterCooling);
} public void BuildGearbox()
{
Thread.Sleep();//模拟耗时
bwmCar.GearBox = new Gearbox(GearboxType.Manual);
} public void BuildTyre()
{
Thread.Sleep();//模拟耗时
bwmCar.Tyres = new List<Tyre>();
for (int i = ; i < ; i++)
{
Tyre tyre = new Tyre(, , , , SpeedGrade.ZR, TreadPattern.Mixed);
bwmCar.Tyres.Add(tyre);
}
} public Car GetCar()
{
return bwmCar;
}
} /// <summary>
/// 奔驰(Benz)构建者(对各个部件有自己的生产工艺)
/// </summary>
public class BenzBuilder : IBuilder
{
private Car benzCar = new Car("Benz", "梅赛德斯-AMG GLC 43 4MATIC");
public void BuildBodywork()
{
Thread.Sleep();//模拟耗时
benzCar.Bodywork = new Bodywork(BodyworkStructure.Load, BodyworkColor.Black, , , );
} public void BuildChassis()
{
Thread.Sleep();//模拟耗时
benzCar.Chassis = new Chassis(, DriveMode.FullTimeAllWheelDrive);
} public void BuildEngine()
{
Thread.Sleep();//模拟耗时
benzCar.Engine = new Engine(, , CoolingMode.WaterCooling);
} public void BuildGearbox()
{
Thread.Sleep();//模拟耗时
benzCar.GearBox = new Gearbox(GearboxType.Automatic);
} public void BuildTyre()
{
Thread.Sleep();//模拟耗时
benzCar.Tyres = new List<Tyre>();
for (int i = ; i < ; i++)
{
Tyre tyre = new Tyre(, , , , SpeedGrade.ZR, TreadPattern.SingleGuide, TyrePosition.Front);
benzCar.Tyres.Add(tyre);
}
for (int i = ; i < ; i++)
{
Tyre tyre = new Tyre(, , , , SpeedGrade.ZR, TreadPattern.SingleGuide, TyrePosition.Rear);
benzCar.Tyres.Add(tyre);
}
} public Car GetCar()
{
return benzCar;
}
}
上述宝马(BWM)和奔驰(Benz)各部件的具体生产工艺并不相同,这体现了总体的生产规范是一样的,但具体的实现是可以不一样的!构建者模式定义中的后半句——相同的构造过程可以创建不同的表示(灵活变化点一)。
同时,上述宝马(BWM)和奔驰(Benz)各部件的生产过程中我们加入了耗时模拟,是为了方便后面体现相同的生产/构建者和相同的工艺(针对同款车型),在不同指导者的指导下可以有不一样的生产流程(但生产规范并没有变,只是流程变了)和生产效率(灵活变化点二)!
到现在,知道了要构建的产品——汽车Car、也有了构建规范——IBuilder接口、还有两个实现了构建规范的具体构建者——宝马(BWM)构建者和奔驰(Benz)构建者,但具体如何组织生产,是先构建车身?还是先构建发动机?还是各个部件同时并行进行构建/生产?这就需要一个构建组织者或叫构建指导者(Director)来做这个事了,由它给出一个总体的构建过程:
/// <summary>
/// 生产指导者(类似车间主任或生产线拉长)
/// </summary>
public class Director
{
/// <summary>
/// 指导构建者生产汽车
/// </summary>
/// <param name="builder">构建者</param>
/// <returns>是否生产成功</returns>
public bool BuildCar(IBuilder builder)
{
try
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
builder.BuildChassis();
builder.BuildEngine();
builder.BuildGearbox();
builder.BuildTyre();
builder.BuildBodywork();
stopwatch.Stop();
Console.WriteLine("{0}{1}生产完成,用时{2}毫秒!\r", builder.GetCar().Name, builder.GetCar().Model, stopwatch.ElapsedMilliseconds);
return true;
}
catch (Exception)
{
return false;
}
}
}
当然,对于给定的同一个构建者,不同的构建指导者(Director)可能会指导其做出不一样的构建过程(灵活变化点二),例如下面这个有多个部件生产线(使用了并行任务)的土豪构建指导者(AsyncDirector):
/// <summary>
/// 具有多条生产线的生产指导者(类似有钱工厂的车间主任或生产线拉长)
/// </summary>
public class AsyncDirector
{
/// <summary>
/// 指导构建者生产汽车
/// </summary>
/// <param name="builder">构建者</param>
/// <returns>是否生产成功</returns>
public bool BuildCar(IBuilder builder)
{
try
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
Parallel.Invoke(builder.BuildChassis, builder.BuildEngine, builder.BuildGearbox, builder.BuildTyre, builder.BuildBodywork);
stopwatch.Stop();
Console.WriteLine("{0}{1}生产完成,用时{2}毫秒!\r", builder.GetCar().Name, builder.GetCar().Model, stopwatch.ElapsedMilliseconds);
return true;
}
catch (Exception)
{
return false;
}
}
}
现在汽车Car、汽车构建规范、构建指导者、具体的构建者都已到位,是时候将它们齐聚一堂搞生产了,我们使用MSUnitTest来齐聚各个角色进行奔驰和宝马的生产测试!
[TestClass]
public class BuilderTest
{
[TestMethod]
public void BuildTest()
{
Car car;
IBuilder benzbuilder = new BenzBuilder();//找(生成)一个奔驰构建者
IBuilder bwmbuilder = new BwmBuilder();//找(生成)一个宝马构建者 #region 普通生产指导者指导生产
Console.WriteLine("普通生产指导者指导生产:\r"); bool isSuccess = false;
Director director = new Director();
if (director.BuildCar(benzbuilder))//把奔驰构建者交给一个普通的构建指导者,以指导进行奔驰汽车构建/生产
{
car = benzbuilder.GetCar();//从奔驰构建者手中拿到构建好的奔驰汽车
Console.Write(car.ToString());
isSuccess = true;
}
Assert.IsTrue(isSuccess); Console.WriteLine("\r"); isSuccess = false;
if (director.BuildCar(bwmbuilder))//把宝马构建者交给一个普通的构建指导者,以指导进行宝马汽车构建/生产
{
car = bwmbuilder.GetCar();//从宝马构建者手中拿到构建好的宝马汽车
Console.Write(car.ToString());
isSuccess = true;
}
Assert.IsTrue(isSuccess);
#endregion Console.WriteLine("\r\r\r"); #region 具有多条生产线的指导者指导生产
Console.WriteLine("具有多条生产线的指导者指导生产:\r"); isSuccess = false;
AsyncDirector asyncDirector = new AsyncDirector();
if (asyncDirector.BuildCar(benzbuilder))//把奔驰构建者交给一个土豪级的构建指导者,以指导进行奔驰汽车构建/生产
{
car = benzbuilder.GetCar();//从奔驰构建者手中拿到构建好的奔驰汽车
Console.Write(car.ToString());
isSuccess = true;
}
Assert.IsTrue(isSuccess); Console.WriteLine("\r"); isSuccess = false;
if (asyncDirector.BuildCar(bwmbuilder))//把宝马构建者交给一个土豪级的构建指导者,以指导进行宝马汽车构建/生产
{
car = bwmbuilder.GetCar();//从宝马构建者手中拿到构建好的宝马汽车
Console.Write(car.ToString());
isSuccess = true;
}
Assert.IsTrue(isSuccess);
#endregion
}
}
下面来看一下生产测试结果:
从测试结果中我们可以看到在构建者(Builder)模式下,产生了两个主要的灵活变化点,可以让相同的构造过程创建出不同的表示的产品,也可以让相同的构建者在不同的构建指导者指导下做出不一样的构建过程和构建效率。
最后再来回顾一下整个构建者(Builder)模式中有哪些角色:要构建的产品(Car)、用于指定构建标准的接口IBuilder(也可以用抽象类)、实现构建标准的具体构建者(BWM和Benz的构建者)、指挥/指导构建的指导者(Director)。
构建者(Builder)模式与工厂方法(FactoryMethod)模式在参与的角色方面咋一看非常相似,工厂方法(FactoryMethod)模式的参与角色有:产品标准/接口(IProduct)、具体的产品(ConcreteProduct)、产品创建者标准(ICreator,只提供一个粗粒度的生产标准产品的工厂级别的接口)、具体的产品创建者(ConcreteCreator,产品的具体创建流程和细节自己决定)。可以发现工厂方法模式与构建者模式最大的区别有以下几点:
- 对要生产的产品制定了产品标准(IProduct),构建者模式中这个并不是必要的,当然也可以制定;
- 产品创建者标准(ICreator)只提供一个粗粒度的标准产品生产接口(FactoryMethod);
- 没有了额外的生产指导者,产品的具体创建流程和细节由具体的产品创建者(ConcreteCreator)自己决定
(PS:发动机和变速箱等类中还有一些方法在这个例子中没有用到,这是为了以后做其他示例用的!)