技术开发 频道

Builder模式应用实践

3  引入Builder模式

 

Builder模式来说,最重要的当然是Build行为的抽象。以本例而言,要创建一个Equipment对象,需要Build的是PortMachine对象,所以我们可以定义两个Build方法的抽象。

void BuildPort(); void BuildMachine(string machineName);

按照这样一个原则,我们可以建立如图1所示的类图。

实现代码如下:

public abstract class EQPBuilder { protected Equipment m_equipment; protected Machine m_machine; public EQPBuilder() { m_equipment = new Equipment(); } public abstract void BuildPort(); public virtual void BuildMachine(string name) { m_machine = new Machine(name); m_equipment.Name = name; m_equipment.Machine = m_machine; } public Equipment GetEQP() { return m_equipment; } } public class InputEQPBuilder:EQPBuilder { public override void BuildPort() { Port port = new InputPort(); m_equipment.AddPort(port); } public override void BuildMachine(string name) { base.BuildMachine(name); m_machine.PortType = "Input"; } } public class OutputEQPBuilder:EQPBuilder { public override void BuildPort() { Port port = new OutputPort(); m_equipment.AddPort(port); } public override void BuildMachine(string name) { base.BuildMachine(name); m_machine.PortType = "Output"; } } public class IOPutEQPBuilder:EQPBuilder { public override void BuildPort() { Port inputPort = new InputPort(); Port outputPort = new OutputPort(); m_equipment.AddPort(inputPort); m_equipment.AddPort(outputPort); } public override void BuildMachine(string name) { base.BuildMachine(name); m_machine.PortType = "InputOutput"; } }

由于Builder子类对于Port对象的创建完全不同,因此我们将父类EQPBuilder中的CreatePort法定义为抽象方法;至于创建Machine对象的CreateMachine方法,则因为具有一些共同的逻辑,可以在父类中提供实现,所以被定义为虚方法,并将相同的逻辑抽象到父类中。EQPBuilder的子类需要重写父类的CreateMachine方法,并在调用父类的CreateMachine方法后,根据创建的Port对象的不同,分别设置Machine对象的PortType值。

 

此外,在抽象类EQPBuilder中,定义了GetEQP方法,用于返回一个Equipment对象,这个对象其实就是EQPBuilder类型对象所创建的产品。由于各个Builder子类返回Equipment对象的实现逻辑完全一样,因而被定义为普通方法。

Builder模式的实现中,已经有了Product(产品)角色Equipment类对象,有了Builder(建造者)角色EQPBuilder类对象,以及它的派生子类。现在还缺少一个Director(指导者)角色,用以引入具体建造者角色,指导完成产品的创建。该角色类似于工厂模式中的工厂对象。因此,我将其定义为LCDFactory,便于调用者理解其职能。

public static class LCDFactory { public static Equipment CreateEQP(EQPBuilder buider, string name) { buider.BuildPort(); buider.BuildMachine(name); return buider.GetEQP(); } }

由于LCDFactory类的静态方法CreateEQP接受的参数是抽象类EQPBuilder,所以指导者角色与建造者角色之间仅存在弱依赖关系,保证了Builder的扩展不会影响产品的创建,类图如图2所示。

与标准的Builder模式不同,为了调用方便,我将EQPBuilder类型中的GetEQP方法也封装到了LCDFactory类中,因此客户端的调用方式应该如下所示。

class Program { static void Main(string[] args) { EQPBuilder builder = new InputEQPBuilder(); Equipment eqp = LCDFactory.CreateEQP(builder, "InputMachine"); eqp.Run(); builder = new IOPutEQPBuilder(); eqp = LCDFactory.CreateEQP(builder, "InputOutputMachine"); eqp.Run(); Console.Read(); } }

4  从容应对扩展

即使创建Equipment的需求发生了变化,应用了Builder模式的设计也能够从容应对。例如,要求创建的Equipment包含一个Machine对象,一个Input类型的Port,两个Output类型的Port,那么我们可以在不修改原有程序集的前提下,新定义一个IO2PutEQPBuilder类,并继承自抽象类EQPBuilder

 

public class IO2PutEQPBuilder:EQPBuilder { public override void BuildPort() { Port inputPort = new InputPort(); Port outputPort1 = new OutputPort(); Port outputPort2 = new OutputPort(); m_equipment.AddPort(inputPort); m_equipment.AddPort(outputPort1); m_equipment.AddPort(outputPort2); } public override void BuildMachine(string name) { base.BuildMachine(name); m_machine.PortType = "InputOutput2"; } }

此时,客户端可以根据传递进来的EQPBuilder类型对象,生产出新的Equipment产品。例如:

class Program { static void Main(string[] args) { EQPBuilder builder = new IO2PutEQPBuilder(); Equipment eqp = LCDFactory.CreateEQP(builder, "InputOutput2Machine"); eqp.Run(); Console.Read(); } }

我们甚至可以引入配置文件,利用反射技术动态创建具体的EQPBuilder对象,从而完全达到松散耦合、开放扩展的目的。本例是项目开发的真实实践,通过对Builder模式的引入,给程序结构带来了有利的变化。这足以证明,如果能够合理地运用设计模式,就足以弥补好的设计与坏的设计之间巨大的鸿沟。

作者简介:

 

张逸,网名Bruce ZhangWayfarer

 

张逸作为一名高级软件工程师,曾先后在中兴通讯、HP任职,参与了AAAAuthorization Authentication Accounting)、BOE-CIMSBOE-Computer Integration Manufacture System)、NCIC-CRMNissan-Customer Relation Management)等项目与模块的设计与开发。作为Microsoft MVPMost Valuable Professional),他主要从事.NET平台下架构设计与开发的工作,熟悉C#ASP.NETWeb Service.NET RemotingWCF等技术。张逸在面向对象领域具有一定的造诣,特别是设计模式、测试驱动开发、极限编程与UML等技术与思想的运用。著有《软件设计精要与模式》一书,由电子工业出版社出版。您可以通过电子邮件地址zhangyi_2003@163.com或者访问他的个人主页http://www.brucezhang.com与他交流。

0
相关文章