在实际生活中,比如房子装修有很多的步骤,比如贴地转、安装柜子、刷乳胶漆等等。通过这些一系列步骤而最终会得到一个结果,就是装修好的房子。 而往往装修的流程都是固定的,比如一般不会衣柜的都不先安装就先刷漆的。而且对于房子装修而言,名义上为装修,但是我们最终得到的装修效果和我们的用材、风格等有很大的关系,但是结果都是一个装修好的房子, 对于这种固定创建步骤而各个步骤可能有不同的实现方式,但最终都得到一个产品的过程,我们就可以使用建造者模式来实现。
定义: 指将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式
类图如下:
3-1Q1141H441X4.gif
在建造者模式中有4个重要的角色。

  • 产品角色: 具体要创建的对象、产品
  • 抽象建造者:定义创建产品的步骤,以及定义返回具体产品的方法。
  • 具体建造者:对抽象建造者的具体实现
  • 指挥者:接收传入具体建造者、对创建步骤的控制,生成具体产品

1、场景描述

先需要装修一个房子, 假设只有贴砖、安装柜子、刷漆三个步骤。 而最终由于设计、选材、工艺等的不同。会有现代和北欧两种不同风格的装修效果。

2、实现

  1. // ***********************具体产品***********************
  2. /// <summary>
  3. /// 具体产品:装修好的房子
  4. /// </summary>
  5. public class House
  6. {
  7. /// <summary>
  8. /// 砖
  9. /// </summary>
  10. public string Brick { get; set; }
  11. /// <summary>
  12. /// 衣柜
  13. /// </summary>
  14. public string Wardrobe { get; set; }
  15. /// <summary>
  16. /// 漆
  17. /// </summary>
  18. public string Paint { get; set; }
  19. }
  20. // ***********************抽象建造者***********************
  21. /// <summary>
  22. /// 抽象建造者
  23. /// </summary>
  24. public abstract class AbstractBuilder
  25. {
  26. /// <summary>
  27. /// 将具体产品(房子)聚合进来
  28. /// </summary>
  29. protected House house = new House();
  30. /// <summary>
  31. /// 贴砖
  32. /// </summary>
  33. public abstract void Tiling();
  34. /// <summary>
  35. /// 安装衣柜
  36. /// </summary>
  37. public abstract void InstallWardrobe();
  38. /// <summary>
  39. /// 刷漆
  40. /// </summary>
  41. public abstract void Paint();
  42. /// <summary>
  43. /// 得到装修好的房子
  44. /// </summary>
  45. /// <returns></returns>
  46. public virtual House GetHouse()
  47. {
  48. return house;
  49. }
  50. }
  51. // ***********************具体建造者***********************
  52. /// <summary>
  53. /// 具体建造者:北欧风格
  54. /// </summary>
  55. public class NordicStyleBuilder : AbstractBuilder
  56. {
  57. public override void InstallWardrobe()
  58. {
  59. house.Wardrobe = "颗粒板衣柜";
  60. }
  61. public override void Paint()
  62. {
  63. house.Paint = "艺术漆";
  64. }
  65. public override void Tiling()
  66. {
  67. house.Wardrobe = "佛山转70*140";
  68. }
  69. }
  70. /// <summary>
  71. /// 具体建造者:现代风格
  72. /// </summary>
  73. public class SmartnessStyleBuilder : AbstractBuilder
  74. {
  75. public override void InstallWardrobe()
  76. {
  77. house.Wardrobe = "实木衣柜";
  78. }
  79. public override void Paint()
  80. {
  81. house.Paint = "乳胶漆";
  82. }
  83. public override void Tiling()
  84. {
  85. house.Wardrobe = "广东转80*1600";
  86. }
  87. }
  88. // ***********************指挥者***********************
  89. /// <summary>
  90. /// 指挥者
  91. /// </summary>
  92. public class Director
  93. {
  94. private IBuilder builder;
  95. public Director(IBuilder builder)
  96. {
  97. this.builder = builder;
  98. }
  99. /// <summary>
  100. /// 控制装修顺序,得到装修好的房子
  101. /// </summary>
  102. /// <returns></returns>
  103. public House GetHouse()
  104. {
  105. builder.Tiling();
  106. builder.InstallWardrobe();
  107. builder.Paint();
  108. return builder.GetHouse();
  109. }
  110. }
  111. // ***********************客户端调用***********************
  112. IBuilder builder = null;
  113. Director director = null;
  114. builder = new NordicStyleBuilder();
  115. director = new Director(builder);
  116. director.GetHouse();
  117. Console.WriteLine("北欧风格装修完成");
  118. builder = new SmartnessStyleBuilder();
  119. director = new Director(builder);
  120. director.GetHouse();
  121. Console.WriteLine("现代风格装修完成");

上面代码类图表示如下:
image.png

3、优缺点

正如所说, 建造者模式将对象的构造与表示分离,产生了很好的解耦作用。具体的实现可以随时进行升级等变化而不影响其他业务逻辑。而且对于不同的建造者,互相之间也不会产生影响。这也体现出了建造者模式很好的封装性。
我们也可以看出来,其实建造者模式也有很大的局限性:它针对的对象的创建,对于具体的建造者而言,都必须遵循指挥者所限制的创建顺序,这一特点就决定了该模式的使用场景。 而且在建造顺序不变化的情况下,建造者模式用起来挺好, 但一当我们需要统一添加新的建造步骤的时候,那所有的具体建造者包括指挥者都需要更改。

4、应用场景

按固定步骤创建复杂对象,而且对于步骤的实现有不同的方式的时候,就可以考虑使用建造者模式。上面说的装修也是很典型的例子。