今天我们讨论一下 Builder 建造者模式,这个 Builder,其实和模板模式非常的像,但是也有区别,那就是在模板模式中父类对子类中的实现进行操作,在父类之中进行一件事情的处理,但是在 Builder 模式之中,父类和子类都不用关心怎么处理,而是用另一个类来完成对这些方法的有机组合,这个类的职责就是监工,规定了到底要怎么样有机的组合这些方法。在监工类(Director)中,将父类组合进去,然后调用父类的操作来抽象的实现一件事情,这就是面向接口(抽象)变成的妙处了,当然这个 Builder 可以使接口也可以是抽象类,在这里我们使用抽象类。
目录

从UML图中可以看出,建造者模式主要解决在软件系统中,有时候面临着"一个复杂对象"的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。
何时使用:一些基本部件不会变,而其组合经常变化的时候。
如何解决:将变与不变分离开。
关键代码:建造者:创建和提供实例,导演:管理建造出来的实例的依赖关系。
一个快餐店的商业案例,其中,一个典型的套餐可以是一个汉堡(Burger)和一杯冷饮(Cold drink)还有小吃(Snack)。汉堡(Burger)可以是素食汉堡(Veg Burger)或鸡肉汉堡(Chicken Burger),它们是包在纸盒(Wrapper)中。冷饮(Cold drink)可以是可口可乐(coke)或百事可乐(pepsi),它们是装在瓶子(bottle)中,小吃有
(FrenchFrice),蛋挞(EggTart)。
我们将创建一个表示食物条目(比如汉堡和冷饮、小吃)的 Item 接口和实现 Item 接口的实体类,以及一个表示食物包装的 Packing 接口和实现 Packing 接口的实体类,汉堡是包在纸盒中,冷饮是装在瓶子中,小吃也是盒装。
然后我们创建一个 Meal 类,带有 Item 的 List 和一个通过结合 Item 来创建不同类型的 Meal 对象的 MealBuilder。我构建了两种Meal类型,作为构造者,你可以使用不同组合构建更多Meal。

Item类:
- internal abstract class Item
- {
- public string Name { get; set; }
- public float Price { get; set; }
- public IPack? Package { get; set; }
- public void SetPrice(float p)=>Price = p;
- }
IPack接口:
- public interface IPack
- {
- public string Pack();
- }
三种包装:
- internal class Bottle : IPack
- {
- public string Pack()
- {
- return "Bottle";
- }
- }
-
- internal class PlasticBag:IPack
- {
- public string Pack() => "PlasticBag";
- }
-
-
-
- internal class Wrapper:IPack
- {
- public string Pack()
- {
- return "Wrapper ";
- }
- }
饮料抽象类:
- internal class Coke:ColdDrink
- {
- public Coke()
- {
- Price = 5.0f;
- Name = "Coke";
- }
- }
两种冷饮:
- internal class Coke:ColdDrink
- {
- public Coke()
- {
- Price = 5.0f;
- Name = "Coke";
- }
- }
-
-
- internal class Pepsi:ColdDrink
- {
- public Pepsi()
- {
- Name = "Pepsi";
- Price = 6.0f;
- }
- }
小吃抽象类:
- internal abstract class Snack : Item
- {
- public Snack() => Package = new Wrapper();
- }
两种小吃:
- internal class EggTart:Snack
- {
- public EggTart()
- {
- Price = 9.99f;
- Name = "Egg Tart";
- }
- }
-
-
- internal class FrenchFrice:Snack
- {
- public FrenchFrice()
- {
- Price = 12.0f;
- Name = "French Frice";
- }
- }
汉堡和小吃类似,就不贴了,然后是Meal:
- internal class Meal
- {
- private List
- Items { get; } = new List
- ();
- public void AddItem(Item item)=>Items.Add(item);
-
- public float GetCost()
- {
- Console.WriteLine("**********************COST************************");
- return Items.Aggregate(0f, (sum, item) => item.Price + sum);
- }
-
- public void ShowItems()
- {
- Console.WriteLine("--------------------------List-----------------------");
- Items.ForEach(item =>
- {
- Console.WriteLine($"Item: {item.Name} \n\t packing: {item.Package?.Pack()}" +
- $"\t\n price: {item.Price}");
- });
- }
- }
构造者MealBuilder:
- internal class MealBuilder
- {
- public Meal PrepareVegMeal()
- {
- Meal meal = new Meal();
- meal.AddItem(new VegBurger());
- meal.AddItem(new Coke());
- meal.AddItem(new FrenchFrice());
- return meal;
- }
- public Meal PrepareNonVegMeal()
- {
- Meal meal = new Meal();
- meal.AddItem(new ChickenBurger());
- meal.AddItem(new Pepsi());
- meal.AddItem(new EggTart());
- return meal;
- }
- }
优点: 1、建造者独立,易扩展。 2、便于控制细节风险。
缺点: 1、产品必须有共同点,范围有限制。 2、如内部变化复杂,会有很多的建造类。
使用场景: 1、需要生成的对象具有复杂的内部结构。 2、需要生成的对象内部属性本身相互依赖。
注意事项:与工厂模式的区别是:建造者模式更加关注与零件装配的顺序。
完整代码:DesignPatternReview