动机: 在我们开发软件或游戏中,有时候面临着"一个复杂对象"的创建工作,这个对象通常由其它一些子对象组成,而且这些子对象经常面临着剧烈的变化.
定义: 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
结构:
四个要素:
1.产品: 包含了一些子对象,如:游戏人物这个产品,它包含了脸容,发型,性别,发型等等的部件,它可以是抽象类,根据需求而定
2.抽象建造者: 可以说它规定了一系列产品部件的创建方法和一个返回产品的方法,当然,只是抽象上
3.具体建造者: 继承了抽象建造者,就是具体对部件创建的实现
4.导演者: 我更钟意理解成控制器,它控制了整个产品的实现过程,而且这个实现过程基本上是不变的,这样才适合Builder模式
例子: 创建一个游戏角色
1.产品:在以下代码中,我没有使用子对象来组合成产品,而是使用简单的字符串表示
/// <summary>
/// 角色父类:规定角色具有的特征
/// </summary>
public class Actor
{
public string Type { get; set; }//角色类型:如天使,恶魔
public string Sex { get; set; }//性别
public string Face { get; set; }//面容
public string Costume { get; set; }//服装
public string Hairstyle { get; set; }//发型
}
2.抽象建造者: 规定了构造游戏角色类型,性别,面容,服装,发型和返回一个产品对象的方法
/// <summary>
/// 抽象建造者:规定了对象的创建方式
/// </summary>
public abstract class ActorBuilder
{
//角色父类
protected Actor actor = new Actor();
//建造方法
public abstract void BuildType();
public abstract void BuildSex();
public abstract void BuildFace();
public abstract void BuildCostume();
public abstract void BuildHairstyle();
//工厂方法,返回一个完整的游戏角色对象
public Actor CreateActor()
{
return this.actor;
}
}
3.具体建造者: 继承了上面的ActorBuilder类,意味着要具体的构造这些部件,这里我使用了两个具体建造者:天使与恶魔
/// <summary>
/// 天使构造器
/// </summary>
public class AngelBuilder:ActorBuilder
{
public override void BuildType()
{
actor.Type = "天使";
}
public override void BuildSex()
{
actor.Sex = "女";
}
public override void BuildFace()
{
actor.Face = "漂亮";
}
public override void BuildCostume()
{
actor.Costume = "白裙";
}
public override void BuildHairstyle()
{
actor.Hairstyle = "披肩长发";
}
}
/// <summary>
/// 恶魔构造器
/// </summary>
public class DevilBuilder:ActorBuilder
{
public override void BuildType()
{
actor.Type = "恶魔";
}
public override void BuildSex()
{
actor.Sex = "妖";
}
public override void BuildFace()
{
actor.Face = "猥琐";
}
public override void BuildCostume()
{
actor.Costume = "黑衣";
}
public override void BuildHairstyle()
{
actor.Hairstyle = "光头";
}
}
4.导演者(控制器): 控制产品的创建过程,记住(因为这是一个主干线,Builder模式发生变化的应该是在产品的子对象变化,所以它基本是不变的)
/// <summary>
/// 控制复杂产品对象的构建:这个过程一般不变
/// </summary>
public class ActorController
{
/// <summary>
/// 创建复杂产品对象
/// </summary>
/// <param name="ab">builder子对象</param>
public Actor Construct(ActorBuilder ab)
{
Actor actor;
//角色的创建过程假设都是这样不变
//都是具有类型,性别,头发,面部,服装
ab.BuildType();
ab.BuildSex();
ab.BuildHairstyle();
ab.BuildFace();
ab.BuildCostume();
actor = ab.CreateActor();
return actor;
}
}
最后:主文件和配置文件: 后面可以直接通过
<span style="white-space:pre"> </span>static void Main(string[] args)
{
//读取配置文件,恶魔
string devil = ConfigurationManager.AppSettings["DevilBuilder"];
//反射生成对象
ActorBuilder ab = Assembly.Load("Builder").CreateInstance(devil) as ActorBuilder;
//通过指挥者创建完整的产品对象
ActorController ac = new ActorController();
Actor actor = ac.Construct(ab);
Console.WriteLine("角色类型:{0}", actor.Type);
Console.WriteLine("性别:{0}", actor.Sex);
Console.WriteLine("面容:{0}", actor.Face);
Console.WriteLine("服装:{0}", actor.Costume);
Console.WriteLine("发型:{0}", actor.Hairstyle);
Console.WriteLine("------------------------------------------------");
//天使
string angel = ConfigurationManager.AppSettings["AngelBuilder"];
ab = Assembly.Load("Builder").CreateInstance(angel) as ActorBuilder;
actor = ac.Construct(ab);
Console.WriteLine("角色类型:{0}", actor.Type);
Console.WriteLine("性别:{0}", actor.Sex);
Console.WriteLine("面容:{0}", actor.Face);
Console.WriteLine("服装:{0}", actor.Costume);
Console.WriteLine("发型:{0}", actor.Hairstyle);
Console.Read();
}
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="DevilBuilder" value="Builder.DevilBuilder"/>
<span style="white-space:pre"> </span> <add key="AngelBuilder" value="Builder.AngelBuilder"/>
</appSettings>
</configuration>
总结,Builder模式的几个要点:
1.Builder模式主要用于"分步骤构建一个发杂的对象",这个的"分步骤"是一个稳定的算法,(如上面控制器创建产品对象的过程),而产品对象的各个部分则经常变化
2.封装变化点,这是面向对象的一个基本原则之一,Builder模式的缺点在于难以应对"分步骤构建"这个需求的变动
3.抽象工厂模式解决的是"系列对象"的需求变化,Builder模式解决"对象部分"的需求变化,再者,Builder模式通常和Composite模式组合使用
这是第四个模式,之前的有三个模式,后面会补上来.