1、什么是建造者模式(生成器模式)
建造者模式是将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
通俗点说就是将一个复杂的对象拆分成一个一个零件,然后按照既定顺序和规则进行组装,最终形成这个相对复杂的对象。相当于组装。
建造者模式特性和功能:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
**建造者模式使用环境:**当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。
**建造者模式注意事项:**建造者模式的使用需要考虑其复杂性,如果产品结构较简单,使用此模式可能会增加系统的复杂性。
建造者模式优点:
客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦。
具体的建造者类之间是相互独立的,容易扩展。
由于具体的建造者是独立的,因此可以对建造过程逐步细化,而不对其他的模块产生任何影响。
建造者模式缺点:
产品的组成部分必须相同,限制了其使用范围。
1.1 建造者模式的4个角色
**Product(产品):**复杂对象本身。
**Builder(抽象建造者):**既可以是抽象类也可以是接口,主要是为了约束和规范具体建造者有哪些零件,并提供一个方法返回组装后的复杂对象。
**ConcreteBuilder(具体建造者):**它继承自Builder(抽象建造者),主要是具体实现父类中的那些零件。也就是说在这个类里就要实际去创建各个零件的具体功能了。
** Director(指挥者):**又称为导演类,在指挥者中不涉及具体产品的信息,只负责保证对象各部分完整创建或按某种顺序创建。客户端一般只需要与指挥者进行交互,在客户端确定具体建造者的类型,并实例化具体建造者对象,然后通过指挥者类的构造函数或者Setter方法将该对象传入指挥者类中。
关系举例说明: 就比如电脑的生产,想要得到一个电脑对于我们来说直接购买即可,这时候我们就是确定了Product(产品)是电脑 。我们购买的商家是Director(指挥者) 因为电脑是商家提供给我们的。商家收到我们的订单后他不可能自己做一台电脑吧,商家肯定是把订单给到厂家,厂家与商家接触的肯定是他们的产品经理吧,产品经理知道电脑是怎样生产的,电脑的生产规格也是产品经理定的,这个厂家产品经理就是Builder(抽象建造者) ,但产品经理不会直接去生产电脑,而是把生产电脑具体的工作内容交给下面的流水线,这个**流水线也就是ConcreteBuilder(具体建造者)。。。**这样举例应该能理清四个的关系吧。关系理清了才好继续往下看。
1.2 建造者模式适用场景
1、当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。
2、相同的方法,不同的执行顺序,产生不同的事件结果时。
3、多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同时。
4、产品类非常复杂,或者产品类中的调用顺序不同产生了不同的效能。
5、创建一些复杂的对象时,这些对象的内部组成构件间的建造顺序是稳定的,但是对象的内部组成构件面临着复杂的变化。
例如:
点餐系统:汉堡、可乐、薯条、炸鸡翅等是不变的,而其组合是经常变化的,生成出各种 "套餐"。
装修系统:改水电、再贴瓷砖、家电、电视墙等,顺序基本不变,用材不同最终生成的产品则不同。
......................
1.3 程序实例(以汉堡店套餐为例)
店里的单品:
/// <summary>
/// 汉堡
/// </summary>
public class Hamburger
{
public string name { get; set; }
}
/// <summary>
/// 饮料
/// </summary>
public class Drink
{
public string name { get; set; }
}
/// <summary>
/// 小食
/// </summary>
public class Snack
{
public string name { get; set; }
}
/// <summary>
/// 调料-番茄酱,辣椒面
/// </summary>
public class Seasoning
{
public string name { get; set; }
}
首先我们需要确定产品也就是---套餐,组合是:汉堡+饮料+小食+调料
/// <summary>
/// 套餐类--要生成的最终产品
/// </summary>
public class SetMenu
{
/// <summary>
/// 汉堡
/// </summary>
public Hamburger Hamburgers { get; set; }
/// <summary>
/// 饮料
/// </summary>
public Drink Drinks { get; set; }
/// <summary>
/// 小食
/// </summary>
public Snack Snacks { get; set; }
/// <summary>
/// 调料
/// </summary>
public List<Seasoning> Seasonings { get; set; }
/// <summary>
///假设是好复杂的逻辑的一个方法
/// </summary>
public void DDD()
{
Console.WriteLine("拿个包装袋");
}
}
定义套餐组成的制作方式(抽象建造者)。做汉堡的方法,做饮料的方法.....
/// <summary>
/// 定义抽象建造者--
/// </summary>
public abstract class TSDBuilder
{
public abstract void BuildHamburger();
public abstract void BuildDrinks();
public abstract void BuildSnack();
public abstract void BuildSeasoning();
/// <summary>
/// 返回的对象实例,可以放到具体建造者类中去返回
/// </summary>
protected SetMenu menu = new SetMenu();
/// <summary>
/// 返回对象本身的方法
/// </summary>
/// <returns></returns>
public SetMenu GetMenu()
{
return menu;
}
}
具体汉堡做成什么汉堡,饮料要什么饮料,由具体建造者(也就是后厨),这里后厨有两个师傅分别会做两个套餐,一个大套餐,一个小套餐。
/// <summary>
/// 具体创建者--创建一个大套餐
/// </summary>
public class BigMenu : TSDBuilder
{
/// <summary>
/// 套餐饮料
/// </summary>
public override void BuildDrinks()
{
base.menu.Drinks = new Drink();
base.menu.Drinks.name = "大杯可乐";
}
/// <summary>
/// 套餐汉堡
/// </summary>
public override void BuildHamburger()
{
base.menu.Hamburgers = new Hamburger();
base.menu.Hamburgers.name = "巨无霸汉堡";
}
/// <summary>
/// 给套餐两包番茄酱
/// </summary>
public override void BuildSeasoning()
{
base.menu.Seasonings = new List<Seasoning>();
base.menu.Seasonings.Add(new Seasoning() { name = "番茄酱" });
base.menu.Seasonings.Add(new Seasoning() { name = "番茄酱" });
}
/// <summary>
/// 套餐小食-烤鸡腿
/// </summary>
public override void BuildSnack()
{
base.menu.Snacks = new Snack();
base.menu.Snacks.name = "烤鸡腿";
}
}
/// <summary>
/// 具体创建者--创建一个小套餐
/// </summary>
public class MinMenu : TSDBuilder
{
/// <summary>
/// 套餐饮料
/// </summary>
public override void BuildDrinks()
{
base.menu.Drinks = new Drink();
base.menu.Drinks.name = "小杯雪碧";
}
/// <summary>
/// 套餐汉堡
/// </summary>
public override void BuildHamburger()
{
base.menu.Hamburgers = new Hamburger();
base.menu.Hamburgers.name = "迷你汉堡";
}
/// <summary>
/// 给套餐一包番茄酱
/// </summary>
public override void BuildSeasoning()
{
base.menu.Seasonings = new List<Seasoning>();
base.menu.Seasonings.Add(new Seasoning() { name = "番茄酱" });
}
/// <summary>
/// 套餐小食-鸡翅根
/// </summary>
public override void BuildSnack()
{
base.menu.Snacks = new Snack();
base.menu.Snacks.name = "鸡翅根";
}
}
后厨做好套餐后由店员打包给客户吧。这个就是指挥者
/// <summary>
/// 指挥者,也就是店员,
/// </summary>
public class Pack
{
private TSDBuilder tSDBuilder = null;
public Pack(TSDBuilder builder)
{
tSDBuilder = builder;
}
/// <summary>
/// 打包方式1,也可直接放到抽象建造者的返回方法里
/// </summary>
public SetMenu PackMethod()
{
tSDBuilder.BuildSnack();
tSDBuilder.BuildHamburger();
tSDBuilder.BuildDrinks();
tSDBuilder.BuildSeasoning();
Console.WriteLine("打包完成:出餐!!");
return tSDBuilder.GetMenu();
}
}
那我们目前有大套餐和小套餐两种可以点。如果要其他套餐就在创建一个具体建造者,也就是再招一个会做其他套餐的师傅。
那么开始点餐
private void WTBtn_Click(object sender, EventArgs e)
{
//到店点餐
Console.WriteLine("我想点一个大份套餐");
//后厨做了套餐
BigMenu big = new BigMenu();
//把套餐给店员
Pack pack = new Pack(big);
//店员打包出餐
var My = pack.PackMethod();
Console.WriteLine("取到餐,打开如下:");
Console.WriteLine(My.Snacks.name);
Console.WriteLine(My.Hamburgers.name);
Console.WriteLine(My.Snacks.name);
Console.WriteLine(JsonConvert.SerializeObject(My.Seasonings));
My.DDD();
//再点一份
Console.WriteLine("\n我又想点一个小份套餐");
//后厨做了套餐
MinMenu Sm = new MinMenu();
//把套餐给店员
Pack pack1 = new Pack(Sm);
//店员打包出餐
var My1 = pack1.PackMethod();
Console.WriteLine("取到餐,打开如下:");
Console.WriteLine(My1.Snacks.name);
Console.WriteLine(My1.Hamburgers.name);
Console.WriteLine(My1.Snacks.name);
Console.WriteLine(JsonConvert.SerializeObject(My1.Seasonings));
}
跟工厂模式区别:
工厂模式关注的是系列的产品,就套餐而言,他更关注是套餐本身,而不是套餐具体的组成。比如用工厂模式以套餐为例就会生产出汉堡店的套餐、炸鸡店的套餐、饭店的套餐。
而建造者模式就关注的是套餐是由什么组成的,排列方式是什么。这也就是大家常说的
工厂模式解决了"多系列产品"的需求变化,而建造者模式解决的是 "产品部分" 的需 求变化
END........................................................................................................................................