建造者模式是一种设计模式,它用于解决复杂对象的构建问题。当一个应用程序需要创建一个由许多不同对象组成的对象时,会发现客户端代码中充满了各种需要组装的部件对象的细节。为了说明这一点,以手机制造系统为例。假设有一个安装在手机供应商处的系统。现在制造商可能会根据触摸屏、操作系统、电池和手写笔等参数来决定创建一部手机。如果有所有这些部件的对象,那么创建具有上述部件任何组合的产品将导致客户端应用程序中非常复杂和难以管理的代码,即决定需要构建什么样的手机的模块。建造者模式旨在解决这样的问题。GoF定义建造者模式为:将复杂对象的构建与其表示分离,以便相同的构建过程可以创建不同的表示。这意味着需要设计一个系统,客户端应用程序只需指定用于创建复杂对象的参数,建造者将负责构建复杂对象。
让看一下建造者模式的类图。然后来看看上述类图中的每个类的作用。
具体建造者(ConcreteBuilder):将创建复杂产品的具体的类。这将跟踪它创建的产品,即组装了哪些部件,这将被客户端用来获取产品对象。
建造者(Builder):这是创建实际产品的接口。
指导者(Director):这是客户端代码,将指定需要组装的部件以创建实际的具体产品。
产品(Product):这是通过组装许多部件创建的对象。
现在让按照建造者模式定义的路线,尝试通过解决之前讨论的类似手机制造商问题来实现一个基本的建造者模式。
让从指定部件的机制开始。让简单地定义一些枚举,以便可以通过组装各种部件类型来创建一个产品。
public enum ScreenType {
ScreenType_TOUCH_CAPACITIVE,
ScreenType_TOUCH_RESISTIVE,
ScreenType_NON_TOUCH
};
public enum Battery {
MAH_1000,
MAH_1500,
MAH_2000
};
public enum OperatingSystem {
ANDROID,
WINDOWS_MOBILE,
WINDOWS_PHONE,
SYMBIAN
};
public enum Stylus {
YES,
NO
};
现在让看看产品类。需要有一个可以通过组装部件来创建的产品,所以让有一个叫做MobilePhone的类,这将是产品类。
class MobilePhone {
// 字段,用于保存部件类型
string phoneName;
ScreenType phoneScreen;
Battery phoneBattery;
OperatingSystem phoneOS;
Stylus phoneStylus;
public MobilePhone(string name) {
phoneName = name;
}
// 公共属性,用于访问手机部件
public string PhoneName {
get { return phoneName; }
}
public ScreenType PhoneScreen {
get { return phoneScreen; }
set { phoneScreen = value; }
}
public Battery PhoneBattery {
get { return phoneBattery; }
set { phoneBattery = value; }
}
public OperatingSystem PhoneOS {
get { return phoneOS; }
set { phoneOS = value; }
}
public Stylus PhoneStylus {
get { return phoneStylus; }
set { phoneStylus = value; }
}
// 方法,用于以自己的表示形式显示手机详细信息
public override string ToString() {
return string.Format("Name: {0}\nScreen: {1}\nBattery {2}\nOS: {3}\nStylus: {4}", PhoneName, PhoneScreen, PhoneBattery, PhoneOS, PhoneStylus);
}
}
现在已经准备好了产品类,让开始创建建造者。建造者应该提供创建任何手机的每个部件的函数。所以让创建一个名为IPhoneBuilder的建造者接口,并看看它。
interface IPhoneBuilder {
void BuildScreen();
void BuildBattery();
void BuildOS();
void BuildStylus();
MobilePhone Phone {
get;
}
}
现在已经准备好了建造者接口,接下来就是需要具体的建造者对象。假设制造商计划生产一部安卓手机和一部Windows手机,所以将需要两个具体的建造者,即AndroidPhoneBuilder和WindowsPhoneBuilder。在这些建造者内部,可以指定想要为每部手机使用的部件类型。
class AndroidPhoneBuilder : IPhoneBuilder {
MobilePhone phone;
public AndroidPhoneBuilder() {
phone = new MobilePhone("Android Phone");
}
#region IPhoneBuilder Members
public void BuildScreen() {
phone.PhoneScreen = ScreenType.ScreenType_TOUCH_RESISTIVE;
}
public void BuildBattery() {
phone.PhoneBattery = Battery.MAH_1500;
}
public void BuildOS() {
phone.PhoneOS = OperatingSystem.ANDROID;
}
public void BuildStylus() {
phone.PhoneStylus = Stylus.YES;
}
// GetResult方法,将返回实际的手机
public MobilePhone Phone {
get { return phone; }
}
#endregion
}
class WindowsPhoneBuilder : IPhoneBuilder {
MobilePhone phone;
public WindowsPhoneBuilder() {
phone = new MobilePhone("Windows Phone");
}
#region IPhoneBuilder Members
public void BuildScreen() {
phone.PhoneScreen = ScreenType.ScreenType_TOUCH_CAPACITIVE;
}
public void BuildBattery() {
phone.PhoneBattery = Battery.MAH_2000;
}
public void BuildOS() {
phone.PhoneOS = OperatingSystem.WINDOWS_PHONE;
}
public void BuildStylus() {
phone.PhoneStylus = Stylus.NO;
}
// GetResult方法,将返回实际的手机
public MobilePhone Phone {
get { return phone; }
}
#endregion
}
最后,让有指导者类。让创建一个指导者类,它将有一个Construct方法,接受一个IPhoneBuilder,然后内部调用具体的建造者的方法。
class Manufacturer {
public void Construct(IPhoneBuilder phoneBuilder) {
phoneBuilder.BuildBattery();
phoneBuilder.BuildOS();
phoneBuilder.BuildScreen();
phoneBuilder.BuildStylus();
}
}
现在已经将构建复杂产品的功能性封装在建造者设计模式中。现在当查看客户端代码时,可以看到创建任何产品是多么的干净。
class Program {
static void Main(string[] args) {
// 让首先创建指导者
Manufacturer newManufacturer = new Manufacturer();
// 让准备好建造者类
IPhoneBuilder phoneBuilder = null;
// 现在让创建一个安卓手机
phoneBuilder = new AndroidPhoneBuilder();
newManufacturer.Construct(phoneBuilder);
Console.WriteLine("A new Phone built:\n\n{0}", phoneBuilder.Phone.ToString());
// 现在让创建一个Windows手机
phoneBuilder = new WindowsPhoneBuilder();
newManufacturer.Construct(phoneBuilder);
Console.WriteLine("A new Phone built:\n\n{0}", phoneBuilder.Phone.ToString());
}
}
现在,如果想创建更多的产品,只需要一个具体的建造者,其余的代码库将保持不变。客户端代码也可以很容易地使用这种模式创建复杂的产品。让看看程序的输出。
在结束之前,让看看应用程序的类图,并将其与建造者模式的类图进行比较。
本文试图描述建造者模式,何时需要它,并提供了建造者模式在C#中的简单实现。