C#建造者模式
一、引言
它主要用于创建一些复杂对象,这些对象内部构建间的建造顺序通常是稳定的,但对象内部的构建通常面临着复杂的变化。
它使得建造代码与表示代码分离,由于建造者隐藏了该产品是如何组装的,所以若需要改变一个产品的内部表示,只需要再定义一个具体的建造者就可以了。
二、目的
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
三、特点
优点:
表述与构建分离。
方便扩展。
接口交互,建造者后期添加或减少不对用户调用产生较大影响。
缺点:
建造者没有等级的划分,结构不清晰。
建造者内部的任务固定,顺序不易颠倒,否则造成很大的影响
四、建造者范例
如上图所示,
1、Director作统一调度和指挥,Director俗称包“包工头”;
2、Builder是建筑的统一规范,它是抽象类。每个建筑者必须继承此类,以符合相关建筑规范。
3、ConcreteBuilder是具体的建筑队,它继承Builder,实现内部规范。
4、Product是产品,它是建筑队索要建造的对象。
包工头,其职责在于指挥和控制建筑队
//指导员(包工头),负责总指挥
class Director
{
//组建建筑队,不建议在这里做,如果这样做了,如果用户想要改变建筑队,就需要修改Director类。耦合性高
//public Director()
//{
// Builder b1 = new ConcreteBuilder1(); //新建一个建筑队1
// Builder b2 = new ConcreteBuilder2(); //新建一个建筑队2
//}
//指挥一个"建筑队"做具体的事情。
public void Construct(Builder builder) //在包工头职责里含有指导指定建筑队进行相关作业
{
builder.BuildPartA(); //指挥建造A
builder.BuildPartB(); //指挥建造B
}
}
//按照情况来说,包公头本应该还有一个职责就是召集若干个建筑队,但是这里不建议
//建造者规范(此为接口,Director与实际建造者沟通就是此接口)
//统一的接口,建筑队必须能造建筑部分A,能早建筑部分B,还可以反馈建造进度
abstract class Builder
{
public abstract void BuildPartA(); //建造A
public abstract void BuildPartB(); //建造B
public abstract Product GetResult();
}
//第一建筑队,符合建筑规范的接口
class ConcreteBuilder1 : Builder
{
private Product product = new Product(); //有具体建筑体
public override void BuildPartA()
{
product.Add("部件A");
}
public override void BuildPartB()
{
product.Add("部件B");
}
public override Product GetResult()
{
return product;
}
}
//第二建筑队,符合建筑规范
class ConcreteBuilder2 : Builder
{
private Product product = new Product(); //有具体的建筑体
public override void BuildPartA()
{
product.Add("部件X");
}
public override void BuildPartB()
{
product.Add("部件Y");
}
public override Product GetResult()
{
return product;
}
}
//产品类,建造者创建的对象
class Product
{
//创建建筑物列表
IList<string> parts = new List<string>();
//建筑物完成部分的添加
public void Add(string part)
{
parts.Add(part);
}
public void Show() //输出建筑物的相关信息
{
Console.WriteLine("\n产品 创建 ----");
foreach (string part in parts)
{
Console.WriteLine(part);
}
}
}
//用户端
static void Main(string[] args)
{
Director director = new Director(); //新建一个指挥者(包工头)
Builder b1 = new ConcreteBuilder1(); //新建一个建筑队1
Builder b2 = new ConcreteBuilder2(); //新建一个建筑队2
director.Construct(b1); //包工头指挥建筑队1进行建造,调用相关函数
Product p1 = b1.GetResult(); //建筑队将建造的结果返回
p1.Show(); //显示出建筑1的细节
director.Construct(b2); //包工头指挥建筑队2进行建造,调用相关函数
Product p2 = b2.GetResult(); //建筑队将建造的结果返回
p2.Show(); //显示出建筑2的细节
Console.Read();
}
五、程序分析
由上面的程序可知。用户具有新建包工头、新建建筑队的权利。可以最大程度放开权限。
并且,包工头与建筑队直接唯一的连接点就是Builder对象。
director.Construct(b1); //b1为实际建筑队
因为Builder是抽象父类,根据里氏转换原则来说。它可以接受所以继承成Builer类的对象,这样便实现了基于接口的编程。
无论后期的建筑队增加还是减少,都不影响Director指挥,因为所有建筑队都是继承Builder的。而建筑队本身完成的事情自然就是在抽象中Builder指定下完成的。
例如:
新建一个建筑队3
在ConsreteBuilder类中的后面添加一个新类
//第三建筑队,符合建筑规范
class ConcreteBuilder3 : Builder
{
private Product product = new Product(); //有具体的建筑体
public override void BuildPartA()
{
product.Add("部件M");
}
public override void BuildPartB()
{
product.Add("部件N");
}
public override Product GetResult()
{
return product;
}
}
//客户端修改一下
static void Main(string[] args)
{
Director director = new Director(); //新建一个指挥者(包工头)
Builder b1 = new ConcreteBuilder1(); //新建一个建筑队1
Builder b2 = new ConcreteBuilder2(); //新建一个建筑队2
Builder b3 = new ConcreteBuilder3(); //新建一个建筑队3
director.Construct(b1); //包工头指挥建筑队1进行建造
Product p1 = b1.GetResult(); //建筑队将建造的结果返回
p1.Show(); //显示出建筑1的细节
director.Construct(b2); //包工头指挥建筑队2进行建造
Product p2 = b2.GetResult(); //建筑队将建造的结果返回
p2.Show(); //显示出建筑2的细节
director.Construct(b3); //包工头指挥建筑队2进行建造
Product p3 = b3.GetResult(); //建筑队将建造的结果返回
p3.Show(); //显示出建筑2的细节
Console.Read();
}
上述表明,新增一个建筑队,只要建筑队类中添加一个派生自Builder类新类。然后在客户端这边使用它即可。整个过程没有对整体框架造成太大影响。
六、总结
建造者模式的关键点在于,通过一个包工头类进行调度指定的建筑队做规范内的相同步骤和相同顺序的事情。
什么意思?
在包工头内的Construct方法如下:
public void Construct(Builder builder)
{
builder.BuildPartA(); //指挥建造A,这是Builder规范内指定的方法1
builder.BuildPartB(); //指挥建造B,这是Builder规范内指定的方法2
}
这也就说明,
包工头是调度指定的建筑队(builder参数接收)按照相同的顺序(先BuilderPartA后BuilderPartB)进行建造。
所有的建筑队受包工头的调度都会遵循这个顺序和任务。
这边引出了建造者模式的特点就是,调用不同的派生类做相同的事情。