建造者模式可以将部件本身和它们的组装过程分开,关注如何一步步创建一个包含多个组成部分的复杂对象,用户只需要指定复杂对象的类型即可得到该对象,而无须知道其内部的具体构造细节。
将一个复杂对象的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。 —《设计模式》GoF
在软件系统中,有时候面临着“一个复杂对象”的创建工作,复杂对象由各个部分的子对象用一定的算法构成; 由于需求的变化,复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。
如何应对这种变化?
如何提供一种“封装机制”来隔离出“复杂对象的各个部分”的变化,从而保持系统中的“稳定构建算法”不随着需求改变而改变?
对象相当于一个待建造的产品,而对象的属性相当于产品的零件,建造产品的过程就是组合零件的过程:由于过程很复杂
过程:客户端负责创建指导者和具体建造者对象。然后,客户把具体建造者对象交给指导者。客户一声令下,指导者操纵建造者开始创建产品。当产品创建完成后,建造者把产品返还给客户端。
具体的构建者可以有多个,它们都继承自Builder父类(或实现这个接口)
这个得好好写写,上课走神了…
游戏中构建一座房子时,房子的构成和构建步骤通常是稳定不变的,但是房子的风格要经常变化,因此这样的的房子的构建可以选用建造者模式。 (示例–GameHouseBuilder) Builder模式主要用于“分步骤构建一个复杂的对象”。在这其中“分步骤”是一个稳定的算法(即Director,如上面例子中的GameManager),而复杂对象的各个部分(即ConcreteBuilder)则经常变化。 AbstractFactory模式解决“系列对象”的需求变化,Builder模式解决“对象部分”的需求变化。Builder模式通常和Composite(组合)模式组合使用。
老师给的源码是用C#写的不带配置文件的,我再添加两句
项目工程结构:
/* 抽象建造者Builder */ namespace GameHouseBuilder { //抽象建造者,规定构建的基本构件和搭建过程 public abstract class Builder { //房屋的部分构造器 public abstract void BuildWall(); public abstract void BuildDoor(); public abstract void BuildWindow(); public abstract void BuildFloor(); public abstract void BuildCeiling(); //获取构建好的房屋--零件组合过程隐含于其中--此过程应该稳定 public abstract House GetHouse(); } } /* 1.具体建造者ClassicalHouseBuilder,还有一个具体构建者代码不贴了 2.在实际项目中,下面的打印语句实际上是为对象添加属性,然后给客户端返回一个按要求封装好的对象; 3.按照建造者模式的定义,客户端指导建造者只是下达一个建造命令,即可得到一个封装好的对象,客户端对建造者中的具体知识并不了解,具体的构件过程由指导者指导 4.另外因为没有具体的业务逻辑要求,实体类House的属性没有被定义 */ namespace GameHouseBuilder { /// <summary> /// 具体的创建者类 /// </summary> public class ClassicalHouseBuilder : Builder { private House house=null; //要构建的具体的产品对象 //房屋的部分构造器 public override void BuildWall(){ Console.WriteLine("构建古典型的墙"); } public override void BuildDoor(){ Console.WriteLine("构建古典型的门"); } public override void BuildWindow(){ Console.WriteLine("构建古典型的窗户"); } public override void BuildFloor(){ Console.WriteLine("构建古典型的地板"); } public override void BuildCeiling(){ Console.WriteLine("构建古典型的天花板"); } //搭建房屋,然后获取构建好的房屋 public override House GetHouse() { //具体组装...... Console.WriteLine("\n返回建造好的古典型的房屋\n"); return house; } } } namespace GameHouseBuilder { /// <summary> /// 建造者模式中的Director,负责管理创建对象的具体过程 /// </summary> public class GameManager { public static House CreateHouse(Builder builder) //biulder为具体的创建者对象 { //零件的构建过程--以下的构建过程相对稳定, 否则不能使用建造者模式 builder.BuildWall(); builder.BuildWall(); builder.BuildWall(); builder.BuildWall(); builder.BuildDoor(); builder.BuildDoor(); builder.BuildWindow(); builder.BuildWindow(); builder.BuildCeiling(); builder.BuildFloor(); //零件的构建过程--如果以上构建过程不稳定,则Builder模式就不适用了 return builder.GetHouse(); //创建完毕各个部分后, 组装--〉返回完整的对象 } } } <?xml version="1.0" encoding="utf-8" ?> <configuration> <appSettings> <add key ="builder" value ="RomanticHouseBuilder"/> </appSettings> </configuration> /* 反射机制需要用到下面两个类库,不要忘了引入; 具体的反射实现细节跟上午用Java做的差不多,也是读取配置文件->拼出全类名->利用反射机制创建对象 这样就做到了完全解耦,以后如果需求再变化,比如加一种新的房屋样式,原来的源码一点也不用改。 */ using System.Reflection; using System.Configuration; namespace GameHouseBuilder { class Program { static void Main(string[] args) { Builder builder; string builderType = ConfigurationSettings.AppSettings["builder"]; builder = (Builder)Assembly.Load("GameHouseBuilder").CreateInstance("GameHouseBuilder." + builderType); //构建具体构造器对象 //也可以利用反射机制避免更改此处代码 //Builder builder = new ClassicalHouseBuilder(); //Builder builder = new RomanticHouseBuilder(); //客户程序只需要调用Director的方法就可以方便的构建对象,更改对象类型只需要改动具体构造器类型 House house = GameManager.CreateHouse(builder); //利用House对象作其他操作 //house.xxx(); Console.ReadLine(); } } }建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,不适合使用建造者模式,因此其使用范围受到一定的限制;
分步骤构建算法(包括零部件的构建与组合,即Director和Builder)如果不稳定,则不适合;
如果产品的内部变化复杂,可能会需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大,增加了系统的理解难度和运行成本。
下一轮复习的时候做做这个题:
4、计算机组装工厂可以将CPU、内存、硬盘、主机、显示器等硬件设备组装在一起构成一台完整的计算机,且构成的计算机可以是笔记本,也可以是台式机,还可以是不提供显示器的服务器主机。对于用户而言,无须关心计算机的组成设备和组装过程,工厂返回给用户的。是完整的计算机对象,使用建造者模式实现计算机组装过程,要求绘制类图并使用C#代码编程模拟实现。