C++设计模式——建造者模式

建造者模式

在GOF的《设计模式 可复用面向对象软件的基础》中是这样说的:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

这句话,似懂非懂的。一个复杂对象的创建,其通常是由很多的子对象构成;如果一个对象能够直接就创建好了,那么也不会称之为复杂对象。由于项目中需求的变化,这个复杂对象的各个部分经常会发生剧烈的变化,但是,不管怎么变化,将它们组合在一起,组成一个复杂的对象的事实是不会变的。建造者模式就提供了一种“封装机制”来将各个对象的变化隔离开,最终,组合成复杂对象的过程是不会变的。

在《大话设计模式》一书中,例举了一个很好的例子————建造小人。建造一个小人,要分为六步:头部、身体、左手、右手、左脚和右脚。与抽象工厂模式不同的是,建造者模式是在Director的控制下一步一步的构造出来的,在建造的过程中,建造者模式可以进行更精细的控制。不管人的头部、身体、左手、右手、左脚或者右脚如何变化,但是最终还是由这几部分组合在一起形成一个人,虽然是同一个建造过程,但是这个人就会有不同的表示,比如,胖子,瘦子,个高的,个低的等等。

UML图

类图如下:

时序图如下:

代码实现


    
    
  1. /*
  2. ** FileName : BuilderPattern
  3. ** Author : Jelly Young
  4. ** Date : 2013/11/22
  5. ** Description : More information, please go to http://www.jellythink.com
  6. */
  7. #include <iostream>
  8. using namespace std ;
  9. typedef enum MANTYPETag
  10. {
  11. kFatMan ,
  12. kThinMan ,
  13. kNormal
  14. } MANTYPE ;
  15. class Man
  16. {
  17. public :
  18. void SetHead ( MANTYPE type ){ m_Type = type ; }
  19. void SetBody ( MANTYPE type ){ m_Type = type ; }
  20. void SetLeftHand ( MANTYPE type ){ m_Type = type ; }
  21. void SetRightHand ( MANTYPE type ){ m_Type = type ; }
  22. void SetLeftFoot ( MANTYPE type ){ m_Type = type ; }
  23. void SetRightFoot ( MANTYPE type ){ m_Type = type ; }
  24. void ShowMan ()
  25. {
  26. switch ( m_Type )
  27. {
  28. case kFatMan :
  29. cout << ”I’m a fat man” << endl ;
  30. return ;
  31. case kThinMan :
  32. cout << ”I’m a thin man” << endl ;
  33. return ;
  34. default :
  35. cout << ”I’m a normal man” << endl ;
  36. return ;
  37. }
  38. }
  39. private :
  40. MANTYPE m_Type ;
  41. };
  42. // Builder
  43. class Builder
  44. {
  45. public :
  46. virtual void BuildHead (){}
  47. virtual void BuildBody (){}
  48. virtual void BuildLeftHand (){}
  49. virtual void BuildRightHand (){}
  50. virtual void BuildLeftFoot (){}
  51. virtual void BuildRightFoot (){}
  52. virtual Man * GetMan (){ return NULL ; }
  53. };
  54. // FatManBuilder
  55. class FatManBuilder : public Builder
  56. {
  57. public :
  58. FatManBuilder (){ m_FatMan = new Man (); }
  59. void BuildHead (){ m_FatMan -> SetHead ( kFatMan ); }
  60. void BuildBody (){ m_FatMan -> SetBody ( kFatMan ); }
  61. void BuildLeftHand (){ m_FatMan -> SetLeftHand ( kFatMan ); }
  62. void BuildRightHand (){ m_FatMan -> SetRightHand ( kFatMan ); }
  63. void BuildLeftFoot (){ m_FatMan -> SetLeftFoot ( kFatMan ); }
  64. void BuildRightFoot (){ m_FatMan -> SetRightFoot ( kFatMan ); }
  65. Man * GetMan (){ return m_FatMan ; }
  66. private :
  67. Man * m_FatMan ;
  68. };
  69. // ThisManBuilder
  70. class ThinManBuilder : public Builder
  71. {
  72. public :
  73. ThinManBuilder (){ m_ThinMan = new Man (); }
  74. void BuildHead (){ m_ThinMan -> SetHead ( kThinMan ); }
  75. void BuildBody (){ m_ThinMan -> SetBody ( kThinMan ); }
  76. void BuildLeftHand (){ m_ThinMan -> SetLeftHand ( kThinMan ); }
  77. void BuildRightHand (){ m_ThinMan -> SetRightHand ( kThinMan ); }
  78. void BuildLeftFoot (){ m_ThinMan -> SetLeftFoot ( kThinMan ); }
  79. void BuildRightFoot (){ m_ThinMan -> SetRightFoot ( kThinMan ); }
  80. Man * GetMan (){ return m_ThinMan ; }
  81. private :
  82. Man * m_ThinMan ;
  83. };
  84. // Director
  85. class Director
  86. {
  87. public :
  88. Director ( Builder * builder ) { m_Builder = builder ; }
  89. void CreateMan ();
  90. private :
  91. Builder * m_Builder ;
  92. };
  93. void Director :: CreateMan ()
  94. {
  95. m_Builder -> BuildHead ();
  96. m_Builder -> BuildBody ();
  97. m_Builder -> BuildLeftHand ();
  98. m_Builder -> BuildRightHand ();
  99. m_Builder -> BuildLeftHand ();
  100. m_Builder -> BuildRightHand ();
  101. }
  102. int main ( int argc , char * argv [])
  103. {
  104. Builder * builderObj = new FatManBuilder ();
  105. Director directorObj ( builderObj );
  106. directorObj . CreateMan ();
  107. Man * manObj = builderObj -> GetMan ();
  108. if ( manObj == NULL )
  109. return 0 ;
  110. manObj -> ShowMan ();
  111. delete manObj ; // 感谢张小张同学的review
  112. manObj = NULL ;
  113. delete builderObj ;
  114. builderObj = NULL ;
  115. return 0 ;
  116. };

上面这个例子比较杂,但是也是建造者模式的应用。下面这个例子是建造者最一般,最简单的实现方法:


    
    
  1. /*
  2. ** FileName : BuilderPattern
  3. ** Author : Jelly Young
  4. ** Date : 2013/11/23
  5. ** Description : More information, please go to http://www.jellythink.com
  6. */
  7. #include <iostream>
  8. #include <vector>
  9. using namespace std ;
  10. class Builder ;
  11. // Product
  12. class Product
  13. {
  14. public :
  15. void AddPart ( const char * info ) { m_PartInfoVec . push_back ( info ); }
  16. void ShowProduct ()
  17. {
  18. for ( std :: vector < const char *>:: iterator item = m_PartInfoVec . begin ();
  19. item != m_PartInfoVec . end (); ++ item )
  20. {
  21. cout <<* item << endl ;
  22. }
  23. }
  24. private :
  25. std :: vector < const char *> m_PartInfoVec ;
  26. };
  27. // Builder
  28. class Builder
  29. {
  30. public :
  31. virtual void BuildPartA () {}
  32. virtual void BuildPartB () {}
  33. virtual Product * GetProduct () { return NULL ; }
  34. };
  35. // ConcreteBuilder
  36. class ConcreteBuilder : public Builder
  37. {
  38. public :
  39. ConcreteBuilder () { m_Product = new Product (); }
  40. void BuildPartA ()
  41. {
  42. m_Product -> AddPart ( "PartA completed" );
  43. }
  44. void BuildPartB ()
  45. {
  46. m_Product -> AddPart ( "PartB completed" );
  47. }
  48. Product * GetProduct () { return m_Product ; }
  49. private :
  50. Product * m_Product ;
  51. };
  52. // Director
  53. class Director
  54. {
  55. public :
  56. Director ( Builder * builder ) { m_Builder = builder ; }
  57. void CreateProduct ()
  58. {
  59. m_Builder -> BuildPartA ();
  60. m_Builder -> BuildPartB ();
  61. }
  62. private :
  63. Builder * m_Builder ;
  64. };
  65. // main
  66. int main ()
  67. {
  68. Builder * builderObj = new ConcreteBuilder ();
  69. Director directorObj ( builderObj );
  70. directorObj . CreateProduct ();
  71. Product * productObj = builderObj -> GetProduct ();
  72. if ( productObj == NULL )
  73. {
  74. return 0 ;
  75. }
  76. productObj -> ShowProduct ();
  77. delete productObj ;
  78. productObj = NULL ; // 谢谢宾零同学的review
  79. delete builderObj ;
  80. builderObj = NULL ;
  81. }

通过比较上面的两个例子,可以很容易的把建造者模式的骨架抽象出来。

使用要点

  1. 建造者模式生成的对象有复杂的内部结构,将分步骤的去构建一个复杂的对象,分多少步是确定的,而每一步的实现是不同的,可能经常发生变化;
  2. 在上面的例子中,我们都看到了最终生成的Man和Product都没有抽象类,这又导出建造者适用的一种情况,当需要创建复杂对象的过程中,复杂对象没有多少共同的特点,很难抽象出来时,而复杂对象的组装又有一定的相似点时,建造者模式就可以发挥出作用。简单的说,可能使用了建造者模式,最终建造的对象可能没有多大的关系,关于这一点,阅读《设计模式 可复用面向对象软件的基础》中的建造者模式时是最有体会的。

总结

一个复杂对象是由多个部件组成的,建造者模式是把复杂对象的创建和部件的创建分别开来,分别用Builder类和Director类来表示。用Director构建最后的复杂对象,而在上面Builder接口中封装的是如何创建一个个部件(复杂对象是由这些部件组成的),也就是说,Director负责如何将部件最后组装成产品。这样建造者模式就让设计和实现解耦了。

刚开始接触建造者模式的时候,最容易把建造者和抽象工厂模式混淆了。由于而这都属于创建型的设计模式,所以二者之间是有公共点的,但是建造者模式注重于对象组合,即不同的小对象组成一个整体的复杂大对象,而抽象工厂模式针对于接口编程,只是对外提供创建对象的工厂接口,不负责对象之后的处理。

建造者模式,是一个比较复杂,不容易权衡的设计模式。大家应该更多的阅读开源代码,理解他人是如何使用该模式的。从实际的应用中学习设计模式。

原文链接:http://www.jellythink.com/archives/98

扫描二维码关注公众号,回复: 3245242 查看本文章

建造者模式

在GOF的《设计模式 可复用面向对象软件的基础》中是这样说的:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

这句话,似懂非懂的。一个复杂对象的创建,其通常是由很多的子对象构成;如果一个对象能够直接就创建好了,那么也不会称之为复杂对象。由于项目中需求的变化,这个复杂对象的各个部分经常会发生剧烈的变化,但是,不管怎么变化,将它们组合在一起,组成一个复杂的对象的事实是不会变的。建造者模式就提供了一种“封装机制”来将各个对象的变化隔离开,最终,组合成复杂对象的过程是不会变的。

在《大话设计模式》一书中,例举了一个很好的例子————建造小人。建造一个小人,要分为六步:头部、身体、左手、右手、左脚和右脚。与抽象工厂模式不同的是,建造者模式是在Director的控制下一步一步的构造出来的,在建造的过程中,建造者模式可以进行更精细的控制。不管人的头部、身体、左手、右手、左脚或者右脚如何变化,但是最终还是由这几部分组合在一起形成一个人,虽然是同一个建造过程,但是这个人就会有不同的表示,比如,胖子,瘦子,个高的,个低的等等。

UML图

类图如下:

时序图如下:

代码实现


  
  
  1. /*
  2. ** FileName : BuilderPattern
  3. ** Author : Jelly Young
  4. ** Date : 2013/11/22
  5. ** Description : More information, please go to http://www.jellythink.com
  6. */
  7. #include <iostream>
  8. using namespace std ;
  9. typedef enum MANTYPETag
  10. {
  11. kFatMan ,
  12. kThinMan ,
  13. kNormal
  14. } MANTYPE ;
  15. class Man
  16. {
  17. public :
  18. void SetHead ( MANTYPE type ){ m_Type = type ; }
  19. void SetBody ( MANTYPE type ){ m_Type = type ; }
  20. void SetLeftHand ( MANTYPE type ){ m_Type = type ; }
  21. void SetRightHand ( MANTYPE type ){ m_Type = type ; }
  22. void SetLeftFoot ( MANTYPE type ){ m_Type = type ; }
  23. void SetRightFoot ( MANTYPE type ){ m_Type = type ; }
  24. void ShowMan ()
  25. {
  26. switch ( m_Type )
  27. {
  28. case kFatMan :
  29. cout << ”I’m a fat man” << endl ;
  30. return ;
  31. case kThinMan :
  32. cout << ”I’m a thin man” << endl ;
  33. return ;
  34. default :
  35. cout << ”I’m a normal man” << endl ;
  36. return ;
  37. }
  38. }
  39. private :
  40. MANTYPE m_Type ;
  41. };
  42. // Builder
  43. class Builder
  44. {
  45. public :
  46. virtual void BuildHead (){}
  47. virtual void BuildBody (){}
  48. virtual void BuildLeftHand (){}
  49. virtual void BuildRightHand (){}
  50. virtual void BuildLeftFoot (){}
  51. virtual void BuildRightFoot (){}
  52. virtual Man * GetMan (){ return NULL ; }
  53. };
  54. // FatManBuilder
  55. class FatManBuilder : public Builder
  56. {
  57. public :
  58. FatManBuilder (){ m_FatMan = new Man (); }
  59. void BuildHead (){ m_FatMan -> SetHead ( kFatMan ); }
  60. void BuildBody (){ m_FatMan -> SetBody ( kFatMan ); }
  61. void BuildLeftHand (){ m_FatMan -> SetLeftHand ( kFatMan ); }
  62. void BuildRightHand (){ m_FatMan -> SetRightHand ( kFatMan ); }
  63. void BuildLeftFoot (){ m_FatMan -> SetLeftFoot ( kFatMan ); }
  64. void BuildRightFoot (){ m_FatMan -> SetRightFoot ( kFatMan ); }
  65. Man * GetMan (){ return m_FatMan ; }
  66. private :
  67. Man * m_FatMan ;
  68. };
  69. // ThisManBuilder
  70. class ThinManBuilder : public Builder
  71. {
  72. public :
  73. ThinManBuilder (){ m_ThinMan = new Man (); }
  74. void BuildHead (){ m_ThinMan -> SetHead ( kThinMan ); }
  75. void BuildBody (){ m_ThinMan -> SetBody ( kThinMan ); }
  76. void BuildLeftHand (){ m_ThinMan -> SetLeftHand ( kThinMan ); }
  77. void BuildRightHand (){ m_ThinMan -> SetRightHand ( kThinMan ); }
  78. void BuildLeftFoot (){ m_ThinMan -> SetLeftFoot ( kThinMan ); }
  79. void BuildRightFoot (){ m_ThinMan -> SetRightFoot ( kThinMan ); }
  80. Man * GetMan (){ return m_ThinMan ; }
  81. private :
  82. Man * m_ThinMan ;
  83. };
  84. // Director
  85. class Director
  86. {
  87. public :
  88. Director ( Builder * builder ) { m_Builder = builder ; }
  89. void CreateMan ();
  90. private :
  91. Builder * m_Builder ;
  92. };
  93. void Director :: CreateMan ()
  94. {
  95. m_Builder -> BuildHead ();
  96. m_Builder -> BuildBody ();
  97. m_Builder -> BuildLeftHand ();
  98. m_Builder -> BuildRightHand ();
  99. m_Builder -> BuildLeftHand ();
  100. m_Builder -> BuildRightHand ();
  101. }
  102. int main ( int argc , char * argv [])
  103. {
  104. Builder * builderObj = new FatManBuilder ();
  105. Director directorObj ( builderObj );
  106. directorObj . CreateMan ();
  107. Man * manObj = builderObj -> GetMan ();
  108. if ( manObj == NULL )
  109. return 0 ;
  110. manObj -> ShowMan ();
  111. delete manObj ; // 感谢张小张同学的review
  112. manObj = NULL ;
  113. delete builderObj ;
  114. builderObj = NULL ;
  115. return 0 ;
  116. };

上面这个例子比较杂,但是也是建造者模式的应用。下面这个例子是建造者最一般,最简单的实现方法:


  
  
  1. /*
  2. ** FileName : BuilderPattern
  3. ** Author : Jelly Young
  4. ** Date : 2013/11/23
  5. ** Description : More information, please go to http://www.jellythink.com
  6. */
  7. #include <iostream>
  8. #include <vector>
  9. using namespace std ;
  10. class Builder ;
  11. // Product
  12. class Product
  13. {
  14. public :
  15. void AddPart ( const char * info ) { m_PartInfoVec . push_back ( info ); }
  16. void ShowProduct ()
  17. {
  18. for ( std :: vector < const char *>:: iterator item = m_PartInfoVec . begin ();
  19. item != m_PartInfoVec . end (); ++ item )
  20. {
  21. cout <<* item << endl ;
  22. }
  23. }
  24. private :
  25. std :: vector < const char *> m_PartInfoVec ;
  26. };
  27. // Builder
  28. class Builder
  29. {
  30. public :
  31. virtual void BuildPartA () {}
  32. virtual void BuildPartB () {}
  33. virtual Product * GetProduct () { return NULL ; }
  34. };
  35. // ConcreteBuilder
  36. class ConcreteBuilder : public Builder
  37. {
  38. public :
  39. ConcreteBuilder () { m_Product = new Product (); }
  40. void BuildPartA ()
  41. {
  42. m_Product -> AddPart ( "PartA completed" );
  43. }
  44. void BuildPartB ()
  45. {
  46. m_Product -> AddPart ( "PartB completed" );
  47. }
  48. Product * GetProduct () { return m_Product ; }
  49. private :
  50. Product * m_Product ;
  51. };
  52. // Director
  53. class Director
  54. {
  55. public :
  56. Director ( Builder * builder ) { m_Builder = builder ; }
  57. void CreateProduct ()
  58. {
  59. m_Builder -> BuildPartA ();
  60. m_Builder -> BuildPartB ();
  61. }
  62. private :
  63. Builder * m_Builder ;
  64. };
  65. // main
  66. int main ()
  67. {
  68. Builder * builderObj = new ConcreteBuilder ();
  69. Director directorObj ( builderObj );
  70. directorObj . CreateProduct ();
  71. Product * productObj = builderObj -> GetProduct ();
  72. if ( productObj == NULL )
  73. {
  74. return 0 ;
  75. }
  76. productObj -> ShowProduct ();
  77. delete productObj ;
  78. productObj = NULL ; // 谢谢宾零同学的review
  79. delete builderObj ;
  80. builderObj = NULL ;
  81. }

通过比较上面的两个例子,可以很容易的把建造者模式的骨架抽象出来。

使用要点

  1. 建造者模式生成的对象有复杂的内部结构,将分步骤的去构建一个复杂的对象,分多少步是确定的,而每一步的实现是不同的,可能经常发生变化;
  2. 在上面的例子中,我们都看到了最终生成的Man和Product都没有抽象类,这又导出建造者适用的一种情况,当需要创建复杂对象的过程中,复杂对象没有多少共同的特点,很难抽象出来时,而复杂对象的组装又有一定的相似点时,建造者模式就可以发挥出作用。简单的说,可能使用了建造者模式,最终建造的对象可能没有多大的关系,关于这一点,阅读《设计模式 可复用面向对象软件的基础》中的建造者模式时是最有体会的。

总结

一个复杂对象是由多个部件组成的,建造者模式是把复杂对象的创建和部件的创建分别开来,分别用Builder类和Director类来表示。用Director构建最后的复杂对象,而在上面Builder接口中封装的是如何创建一个个部件(复杂对象是由这些部件组成的),也就是说,Director负责如何将部件最后组装成产品。这样建造者模式就让设计和实现解耦了。

刚开始接触建造者模式的时候,最容易把建造者和抽象工厂模式混淆了。由于而这都属于创建型的设计模式,所以二者之间是有公共点的,但是建造者模式注重于对象组合,即不同的小对象组成一个整体的复杂大对象,而抽象工厂模式针对于接口编程,只是对外提供创建对象的工厂接口,不负责对象之后的处理。

建造者模式,是一个比较复杂,不容易权衡的设计模式。大家应该更多的阅读开源代码,理解他人是如何使用该模式的。从实际的应用中学习设计模式。

原文链接:http://www.jellythink.com/archives/98

猜你喜欢

转载自blog.csdn.net/weixin_28712713/article/details/82228021