参考网站:https://blog.csdn.net/liaoshengg/article/details/82078997
参考网站:https://blog.csdn.net/lxt610/article/details/81325731
建造者注重物体创建过程的理解:http://dingxiaowei.cn/2017/05/16/

一、定义

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
图片.png
理解:
以创建角色为例,角色组装可以使用工厂模式来生成角色对象,但是如果要对角色(双方士兵)作不同差异功能的时候就要再次分开写两个新的工厂类(我方士兵工厂类,敌方士兵工厂类),如果要对士兵类添加新的功能,则可以往工厂类添加方法。但是这样做会让工厂管理类越来越复杂
这时可以用到建造者模式了:将一个复杂对象的构建流程与它的对象表现分离出来,让相同的构建流程可以产生出不同的对象行为的表现。
比如说配置一辆车子时,都会按照一定的步骤来组装准备车架-> 外观烤漆 -> 将引擎放入车架 -> 装入内装椅,此时就把组装的流程定义好了,但是具体的需求完全可以由我们来设定

二、适用场景

  • 需要生成的产品对象有复杂的内部结构,这些产品对象具备共性;
  • 隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的产品;

    三、组成部分

    建造者中的角色如下:
    1、Builder:给出一个抽象/接口,以规范产品对象的各个组成成分的建造。这个接口规定要实现复杂对象的哪些部分的创建,并不涉及具体的对象部件的创建。
    2、ConcreteBuilder:实现Builder接口,针对不同的商业逻辑,具体化复杂对象的各部分的创建。 在建造过程完成后,提供产品的实例。
    3、Director:调用具体建造者来创建复杂对象的各个部分,在指导者中不涉及具体产品的信息,只负责保证对象各部分完整创建或按某种顺序创建。该类有一个方法,明确定义对象组装的流程,即调用Builder接口方法的顺序
    4、Product:所要创建的复杂对象, 必须提供方法让Builder类可以将各部分功能设置给它

    四、简单案例

    1. /// <summary>
    2. /// 产品类,由多个部件组成
    3. /// </summary>
    4. public class Product
    5. {
    6. /// <summary>
    7. /// 产品部件集合
    8. /// </summary>
    9. IList<string> parts = new List<string>();
    10. /// <summary>
    11. /// 添加产品部件
    12. /// </summary>
    13. /// <param name="part"></param>
    14. public void Add(string part)
    15. {
    16. parts.Add(part);
    17. }
    18. public void Show()
    19. {
    20. Console.WriteLine("\n产品 创建 ==>>>");
    21. foreach (string part in parts)
    22. {
    23. Console.WriteLine(part);
    24. }
    25. }
    26. }
    1. /// <summary>
    2. /// 抽象建造者类
    3. /// 确定产品的两个部件PartA、PartB,
    4. /// 并声明一个得到产品建造后果的方法GetResult.
    5. /// </summary>
    6. public abstract class Builder
    7. {
    8. public abstract void BuildPartA();
    9. public abstract void BuildPartB();
    10. public abstract Product GetResult();
    11. }
    1. class ConcreteBuilder1 : Builder
    2. {
    3. private Product product = new Product();
    4. public override void BuildPartA()
    5. {
    6. product.Add("部件A");
    7. }
    8. public override void BuildPartB()
    9. {
    10. product.Add("部件B");
    11. }
    12. public override Product GetResult()
    13. {
    14. return product;
    15. }
    16. }
    17. public class ConcreteBuilder2 : Builder
    18. {
    19. private Product product = new Product();
    20. public override void BuildPartA()
    21. {
    22. product.Add("X部件");
    23. }
    24. public override void BuildPartB()
    25. {
    26. product.Add("Y部件");
    27. }
    28. public override Product GetResult()
    29. {
    30. return product;
    31. }
    32. }
    1. class Director
    2. {
    3. /// <summary>
    4. /// 用来指挥创建过程
    5. /// </summary>
    6. /// <param name="builder"></param>
    7. public void Construct(Builder builder)
    8. {
    9. builder.BuildPartA();
    10. builder.BuildPartB();
    11. }
    12. }

    ```csharp Director director = new Director(); Builder b1 = new ConcreteBuilder1(); Builder b2 = new ConcreteBuilder2();

director.Construct(b1); Product p1 = b1.GetResult(); p1.Show();

director.Construct(b2); Product p2 = b2.GetResult(); p2.Show(); ———————————————— 输出: 产品 创建 ==>>> 部件A 部件B 产品 创建 ==>>> X部件 Y部件

  1. <a name="uPfZP"></a>
  2. ## 五、优缺点
  3. 优点:<br />1.易于解耦,将产品本身与产品创建过程进行解耦,可以使用相同的创建过程来得到不同的产品。也就说细节依赖抽象。<br />2.易于精确控制对象的创建,将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰<br />3.易于拓展,增加新的具体建造者无需修改原有类库的代码,易于拓展,符合“开闭原则“。<br />**综述:**每一个具体建造者都相对独立,而与其他的具体建造者无关,因此可以很方便地替换具体建造者或增加新的具体建造者,用户使用不同的具体建造者即可得到不同的产品对象。<br />缺点<br /> 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似;如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。<br /> 如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大。
  4. <a name="nJY5k"></a>
  5. ## 六、Unity应用案例
  6. ```csharp
  7. public class UIView
  8. {
  9. protected Text mText;
  10. protected Text mBtnText;
  11. protected Image mImage;
  12. public void Init(Transform transform)
  13. {
  14. mText = Instantiate(transform, "UIView/MyText").GetComponent<Text>();
  15. Button button = Instantiate(transform, "UIView/Button").GetComponent<Button>();
  16. mBtnText = transform.Find("Button(Clone)/Text").GetComponent<Text>();
  17. mImage = Instantiate(transform, "UIView/Image").GetComponent<Image>();
  18. }
  19. protected GameObject Load(string path)
  20. {
  21. return Resources.Load<GameObject>(path);
  22. }
  23. protected GameObject Instantiate(Transform parent, string path)
  24. {
  25. GameObject go = GameObject.Instantiate(Load(path));
  26. GameObject goNew = GameObject.Find("");
  27. go.transform.SetParent(parent, false);
  28. //go.transform.localScale = Vector3.one;
  29. //go.transform.position = go.transform.position;
  30. return go;
  31. }
  32. }
  1. public class Product
  2. {
  3. List<UIView> parts = new List<UIView>();
  4. public void Add(UIView go)
  5. {
  6. if (go is ConcreteBuilder1)
  7. parts.Add(go as ConcreteBuilder1);
  8. if (go is ConcreteBuilder2)
  9. parts.Add(go as ConcreteBuilder2);
  10. }
  11. public void Show()
  12. {
  13. foreach (UIView go in parts)
  14. {
  15. if (go is ConcreteBuilder1)
  16. {
  17. ConcreteBuilder1 b1 = go as ConcreteBuilder1;
  18. b1.BuilderMethodA();
  19. }
  20. if (go is ConcreteBuilder2)
  21. {
  22. (go as ConcreteBuilder2).BuilderMethodA();
  23. }
  24. }
  25. }
  26. }
  1. public abstract class Builder : UIView
  2. {
  3. public abstract void BuilderMethodA();
  4. public abstract Product GetResult();
  5. }
  1. public class ConcreteBuilder1 : Builder
  2. {
  3. private Product product = new Product();
  4. public override void BuilderMethodA()
  5. {
  6. mText.text = "建造者A";
  7. mBtnText.text = "建造者A按钮";
  8. mImage.color = Color.red;
  9. }
  10. public override Product GetResult()
  11. {
  12. return product;
  13. }
  14. }
  15. public class ConcreteBuilder2 : Builder
  16. {
  17. private Product product = new Product();
  18. public override void BuilderMethodA()
  19. {
  20. mText.text = "建造者B";
  21. mBtnText.text = "建造者B按钮";
  22. mImage.color = Color.green;
  23. }
  24. public override Product GetResult()
  25. {
  26. return product;
  27. }
  28. }
  1. public class Director
  2. {
  3. public void Construct(Builder builder)
  4. {
  5. builder.BuilderMethodA();
  6. }
  7. }
  1. public class Test : MonoBehaviour {
  2. void OnGUI()
  3. {
  4. if (GUI.Button(new Rect(100, 100, 120, 50), "按钮1"))
  5. {
  6. Director director = new Director();
  7. Builder b1 = new ConcreteBuilder1();
  8. b1.Init(this.transform);
  9. director.Construct(b1);
  10. Product p1 = b1.GetResult();
  11. p1.Show();
  12. }
  13. if (GUI.Button(new Rect(100, 200, 120, 50), "按钮2"))
  14. {
  15. Director director = new Director();
  16. Builder b2 = new ConcreteBuilder2();
  17. b2.Init(this.transform);
  18. director.Construct(b2);
  19. Product p2 = b2.GetResult();
  20. p2.Show();
  21. }
  22. }
  23. }

如果在此基础上有对于建造过程有所限制呢?例如创建了A则不能创建B,或者创建了A则必须创建B
创建过程校验的理解:http://dingxiaowei.cn/2017/05/16/

工厂模式VS建造者模式

如果刚接触建造者模式,可能会有个疑惑,同样都是创建型模式,而且都是创建对象这种创建型模式,那么它们之间的区别是什么呢?从我的理解来讲,我觉得工厂模式是注重创建不同类型的产品,从宏观上体现出差别,举个例子,还是汽车厂商通用公司,它下面有各种类型的汽车品牌工厂,雪佛兰、别克、凯迪拉克等工厂,每个工厂生产出来的产品是不一样的,而建造者模式我认为是体现了”建造”这样的流程,例如我要生产一个汽车,那么汽车厂在生产的过程是一条流水线,先生产什么,再生产什么,最后有装配车间去组装,重点是在建造的过程上。所以说差异性在以下两个方面:

  • 意图不同
    在工厂模式中,我们关注的是一个产品整体,无需关心产品各个部分是如何生产出来的,但建造者模式中,一个具体产品的生产是依赖各个部件的产生以及装配顺序,它关注的是由”零部件一步一步地组装产品对象”。简单来说,工厂模式是一个对象创建的组线条应用,建造者模式则是通过细线条勾勒出一个复杂对象,关注的是产品组成部分的创建过程。工厂方法模式注重产品本身,而建造者模式注重产品创建过程。
  • 复杂度不同
    工厂方法模式的产品一般是单一性质产品,例如各个不同品牌的汽车,他们都是汽车模样,而建造者模式创建一个复合产品,它由各个零部件组成,部件不同产品对象也当然不同。不是说工厂模式创建的对象简单,而是只他们的粒度大小不同。一般来说,工厂方法模式的对象比较粗,建造者模式的产品对象粒度比较细。

两者的区别有了,那么在具体应用中,我们该如何选择呢?使用工厂模式创建对象,还是用建造者模式来创建对象。这取决于我们在做设计的意图,是关心最终的产品的零部件生产、组装过程,还是说想得到不同的产品。就像上面举例的创建一个角色,我们需要给他创建各个零部件,然后组合成一个角色,还记得工厂模式的例子嘛,生产不同类型的武器,生产不同品牌的汽车,Unity中创建不同类型的UI(Button、Text、Toggle等)。现在你知道这两者的本质区别了嘛。