几种常见的设计模式(含C++代码)

本文部分转载于https://blog.csdn.net/hechao3225/article/details/71366058

本文介绍几种常用的设计模式并给出C++实现。

 

1.单例模式

作用:保证一个类只有一个实例,并提供一个访问它的全局访问点,使得系统中只有唯一的一个对象实例。

应用:常用于管理资源,如日志、线程池

实现要点:

在类中,要构造一个实例,就必须调用类的构造函数,并且为了保证全局只有一个实例,

需防止在外部调用类的构造函数而构造实例,需要将构造函数的访问权限标记为private,

同时阻止拷贝创建对象时赋值时拷贝对象,因此也将它们声明并权限标记为private;

另外,需要提供一个全局访问点,就需要在类中定义一个static函数,返回在类内部唯一构造的实例。

 
  1. class Singleton{

  2. public:

  3. static Singleton& getInstance(){

  4. static Singleton instance;

  5. return instance;

  6. }

  7. void printTest(){

  8. cout<<"do something"<<endl;

  9. }

  10. private:

  11. Singleton(){}//防止外部调用构造创建对象

  12. Singleton(Singleton const &singleton);//阻止拷贝创建对象

  13. Singleton& operator=(Singleton const &singleton);//阻止赋值对象

  14. };

  15. int main()

  16. {

  17. Singleton &a=Singleton::getInstance();

  18. a.printTest();

  19. return 0;

  20. }

 

  1.  

首先,构造函数声明成private的目的是只允许内部调用,getInstance()中的静态局部变量创建时调用,但不允许外部调用构造创建第二个实例;

 

然后,拷贝构造和拷贝赋值符是声明成了private而不给出定义,其目的是阻止拷贝,如果企图通过拷贝构造来创建第二个实例,编译器会报错。

阻止拷贝的另一种写法是声明后接一个"=delete",也能起到相同的作用(C++11)。

 

2.工厂模式

工厂模式包括三种:简单工厂模式、工厂方法模式、抽象工厂模式。

工厂模式的主要作用是封装对象的创建,分离对象的创建和操作过程,用于批量管理对象的创建过程,便于程序的维护和扩展。

(1)简单工厂模式

简单工厂是工厂模式最简单的一种实现,对于不同产品的创建定义一个工厂类,将产品的类型作为参数传入到工厂的创建函数,根据类型分支选择不同的产品构造函数。

 
  1. //简单工厂模式

  2. typedef enum ProductTypeTag

  3. {

  4. TypeA,

  5. TypeB,

  6. TypeC

  7. }PRODUCTTYPE;

  8. class Product//产品抽象基类

  9. {

  10. public:

  11. virtual void Show() = 0;

  12. };

  13. class ProductA : public Product

  14. {

  15. public:

  16. void Show()

  17. {

  18. cout<<"I'm ProductA"<<endl;

  19. }

  20. };

  21. class ProductB : public Product

  22. {

  23. public:

  24. void Show()

  25. {

  26. cout<<"I'm ProductB"<<endl;

  27. }

  28. };

  29. class ProductC : public Product

  30. {

  31. public:

  32. void Show()

  33. {

  34. cout<<"I'm ProductC"<<endl;

  35. }

  36. };

  37. class Factory//工厂类

  38. {

  39. public:

  40. Product* CreateProduct(PRODUCTTYPE type)

  41. {

  42. switch (type)

  43. {

  44. case TypeA:

  45. return new ProductA();

  46. case TypeB:

  47. return new ProductB();

  48. case TypeC:

  49. return new ProductC();

  50. default:

  51. return NULL;

  52. }

  53. }

  54. };

  55. int main()

  56. {

  57. Factory productCreator;

  58. Product *productA=productCreator.CreateProduct(TypeA);

  59. Product *productB=productCreator.CreateProduct(TypeB);

  60. Product *productC=productCreator.CreateProduct(TypeC);

  61. productA->Show();

  62. productB->Show();

  63. productC->Show();

  64. if(productA){

  65. delete productA;

  66. productA=NULL;

  67. }

  68. if(productB){

  69. delete productB;

  70. productB=NULL;

  71. }

  72. if(productC){

  73. delete productC;

  74. productC=NULL;

  75. }

  76. return 0;

  77. }


(2)工厂方法模式

 

其实这才是正宗的工厂模式,简单工厂模式只是一个简单的对创建过程封装。工厂方法模式在简单工厂模式的基础上增加对工厂的基类抽象,不同的产品创建采用不同的工厂创建(从工厂的抽象基类派生),这样创建不同的产品过程就由不同的工厂分工解决:FactoryA专心负责生产ProductA,FactoryB专心负责生产ProductB,FactoryA和FactoryB之间没有关系;如果到了后期,如果需要生产ProductC时,我们则可以创建一个FactoryC工厂类,该类专心负责生产ProductC类产品。

该模式相对于简单工厂模式的优势在于:便于后期产品种类的扩展。

 
  1. //工厂方法模式

  2. typedef enum ProductTypeTag

  3. {

  4. TypeA,

  5. TypeB,

  6. TypeC

  7. }PRODUCTTYPE;

  8. class Product//产品抽象基类

  9. {

  10. public:

  11. virtual void Show() = 0;

  12. };

  13. class ProductA : public Product

  14. {

  15. public:

  16. void Show()

  17. {

  18. cout<<"I'm ProductA"<<endl;

  19. }

  20. };

  21. class ProductB : public Product

  22. {

  23. public:

  24. void Show()

  25. {

  26. cout<<"I'm ProductB"<<endl;

  27. }

  28. };

  29. class Factory//工厂类

  30. {

  31. public:

  32. virtual Product *createProduct()=0;

  33. };

  34. class FactoryA:public Factory{

  35. public:

  36. Product *createProduct(){

  37. return new ProductA();

  38. }

  39. };

  40. class FactoryB:public Factory{

  41. public:

  42. Product *createProduct(){

  43. return new ProductB();

  44. }

  45. };

  46. class FactoryC:public Factory{

  47. public:

  48. Product *createProduct(){

  49. return new ProductC();

  50. }

  51. };

  52. int main()

  53. {

  54. Factory *factoryA=new FactoryA();

  55. Product *productA = factoryA->createProduct();

  56. productA->Show();

  57. Factory *factoryB=new FactoryB();

  58. Product *productB = factoryB->createProduct();

  59. productB->Show();

  60. if (factoryA)

  61. {

  62. delete factoryA;

  63. factoryA = NULL;

  64. }

  65. if (factoryB)

  66. {

  67. delete factoryB;

  68. factoryB = NULL;

  69. }

  70. if (productA)

  71. {

  72. delete productA;

  73. productA = NULL;

  74. }

  75. if (productB)

  76. {

  77. delete productB;

  78. productB = NULL;

  79. }

  80. return 0;

  81. }

 

(3)抽象工厂模式

抽象工厂模式对工厂方法模式进行了更加一般化的描述。工厂方法模式适用于产品种类结构单一的场合,为一类产品提供创建的接口;而抽象工厂方法适用于产品种类结构多的场合,就是当具有多个抽象产品类型时,抽象工厂便可以派上用场。

抽象工厂模式更适合实际情况,受生产线所限,让低端工厂生产不同种类的低端产品,高端工厂生产不同种类的高端产品。

 
  1. //抽象工厂模式

  2. class ProductA

  3. {

  4. public:

  5. virtual void Show() = 0;

  6. };

  7. class ProductA1 : public ProductA//A类低端产品

  8. {

  9. public:

  10. void Show()

  11. {

  12. cout<<"I'm ProductA1"<<endl;

  13. }

  14. };

  15. class ProductA2 : public ProductA//A类高端产品

  16. {

  17. public:

  18. void Show()

  19. {

  20. cout<<"I'm ProductA2"<<endl;

  21. }

  22. };

  23. class ProductB

  24. {

  25. public:

  26. virtual void Show() = 0;

  27. };

  28. class ProductB1 : public ProductB//B类低端产品

  29. {

  30. public:

  31. void Show()

  32. {

  33. cout<<"I'm ProductB1"<<endl;

  34. }

  35. };

  36. class ProductB2 : public ProductB//B类高端产品

  37. {

  38. public:

  39. void Show()

  40. {

  41. cout<<"I'm ProductB2"<<endl;

  42. }

  43. };

  44. class Factory

  45. {

  46. public:

  47. virtual ProductA *CreateProductA() = 0;

  48. virtual ProductB *CreateProductB() = 0;

  49. };

  50. class Factory1 : public Factory//1号工厂用于生产低端产品

  51. {

  52. public:

  53. ProductA *CreateProductA()

  54. {

  55. return new ProductA1();

  56. }

  57. ProductB *CreateProductB()

  58. {

  59. return new ProductB1();

  60. }

  61. };

  62. class Factory2 : public Factory//2号工厂用于生产高端产品

  63. {

  64. ProductA *CreateProductA()

  65. {

  66. return new ProductA2();

  67. }

  68. ProductB *CreateProductB()

  69. {

  70. return new ProductB2();

  71. }

  72. };

  73. int main()

  74. {

  75. Factory *factory1 = new Factory1();

  76. ProductA *productA1 = factory1->CreateProductA();

  77. ProductB *productB1 = factory1->CreateProductB();

  78. productA1->Show();

  79. productB1->Show();

  80. Factory *factory2 = new Factory2();

  81. ProductA *productA2 = factory2->CreateProductA();

  82. ProductB *productB2 = factory2->CreateProductB();

  83. productA2->Show();

  84. productB2->Show();

  85. if (factory1)

  86. {

  87. delete factory1;

  88. factory1 = NULL;

  89. }

  90. if (productA1)

  91. {

  92. delete productA1;

  93. productA1= NULL;

  94. }

  95. if (productB1)

  96. {

  97. delete productB1;

  98. productB1 = NULL;

  99. }

  100. if (factory2)

  101. {

  102. delete factory2;

  103. factory2 = NULL;

  104. }

  105. if (productA2)

  106. {

  107. delete productA2;

  108. productA2 = NULL;

  109. }

  110. if (productB2)

  111. {

  112. delete productB2;

  113. productB2 = NULL;

  114. }

  115. }

3 策略模式

转载于https://blog.csdn.net/lh844386434/article/details/16825861

策略模式也是一种非常常用的设计模式,而且也不复杂。下面我们就来看看这种模式。

 

定义:策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。

角色:
    抽象策略角色(Strategy): 抽象策略类。
    具体策略角色(ConcreteStrategy):封装了继续相关的算法和行为。
    环境角色(Context):持有一个策略类的引用,最终给客户端调用。

UML图:

                几种常见的设计模式(含C++代码)

事例: (该事例改编自一道网络设计模式面试题)

     如现在你是一个设计师,你正在设计一种空调。但是你们的空调要支持3种模式。冷风模式(ColdWind), 热风模式(WramWind),无风模式(NoWind)。
当选择ColdWind模式,将输送冷风;当选择WarmWind模式,将输送热风;在选择NoWind模式时,空调什么都不做。你将考虑如何为空调设计应用程序?如果将来空调需要增加支持新的模式呢?

这道面试题,其实可以用各种模式实现,然而在这里我理解策略模式比较合适。我们将冷风模式,和热风模式以及无风模式可以理解为各种不同的算法。显然策略模式非常符合。

这里ColdWind, WramWind, NoWind 其实就是ConcreteStrategy。 IWnd 是抽象策略类。 所以我们开始这么封装我们策略类

 
  1. #include <iostream>

  2. using namespace std;

  3. #define free_ptr(p) \

  4. if(p) delete p; p = NULL;

  5.  
  6. class IWind{

  7. public:

  8. virtual ~IWind(){};

  9. virtual void blowWind() = 0;

  10. };

  11.  
  12. class ColdWind : public IWind{

  13. public:

  14. void blowWind(){

  15. cout<<"Blowing cold wind!"<<endl;

  16. };

  17. };

  18.  
  19. class WarmWind : public IWind{

  20. public:

  21. void blowWind(){

  22. cout<<"Blowing warm wind!"<<endl;

  23. }

  24. };

  25.  
  26. class NoWind : public IWind{

  27. public:

  28. void blowWind(){

  29. cout<<"No Wind!"<<endl;

  30. }

  31. };

然后我们实现一个windmode 的类,作为 wind 系列的环境类:

 
  1. class WindMode{

  2. public:

  3. WindMode(IWind* wind): m_wind(wind){};

  4. ~WindMode(){free_ptr(m_wind);}

  5. void blowWind(){

  6. m_wind->blowWind();

  7. };

  8. private:

  9. IWind* m_wind;

  10. };

最后客户端代码:

 
  1. int main(int argc, char* argv[])

  2. {

  3. WindMode* warmWind = new WindMode(new WarmWind());

  4. WindMode* coldWind = new WindMode(new ColdWind());

  5. WindMode* noWind = new WindMode(new NoWind());

  6.  
  7. warmWind->BlowWind();

  8. coldWind->BlowWind();

  9. noWind->BlowWind();

  10.  
  11. free_ptr(warmWind);

  12. free_ptr(coldWind);

  13. free_ptr(noWind);

  14. system("pause");

  15. return 0;

  16. }

(这个实例网上也有人用命令模式实现。命令模式请看我后面的博客。把冷风,热风,无风作为一种命令。当然这是另外一种思路,也未尝不可。但是我觉得如果采用命令模式。类的个数会相应增加(增加系列的命令类),造成额外的开销。当添加一个新模式的时候,你需要添加的类过多。或多或少不是那么明智。所以我个人认为在这里策略模式更好一些。)

 

总的说来策略模式:

优点:
1、 使用策略模式可以避免使用多重条件转移语句。多重转移语句不易维护。
2、 策略模式让你可以动态的改变对象的行为,动态修改策略

缺点:
1、客户端必须知道所有的策略类,并自行决定使用哪一个策略类。
2、类过多---策略模式造成很多的策略类,每个具体策略类都会产生一个新类。(这点可以通过享元模式来克服类过多)

模式定义:

        命令模式将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。

        命令对象将动作和接受者包进对象中,这个对象只暴露一个execute()方法。

        当需要将发出请求的对象和执行请求的对象解耦的时候,使用命令模式。

模式结构:

几种常见的设计模式(含C++代码)

举例:

        遥控器上有一个插槽,可以放上不同的装置,然后用按钮控制。我们这里放置电灯,并有开和关按钮。可以命令模式实现。

UML设计:

几种常见的设计模式(含C++代码)

 

        其中,RemoteControl为遥控器,LightOnCommand为开灯请求对象,LightOffCommand为关灯请求对象,他们继承自基类Command,这样设计可以使插槽在以后防止其他的装置。

 
  1. #include <iostream>

  2.  
  3. using namespace std;

  4.  
  5. //电灯类

  6. class Light

  7. {

  8. public:

  9. void on()

  10. {

  11. cout << "Light on !" << endl;

  12. }

  13.  
  14. void off()

  15. {

  16. cout << "Light off !" << endl;

  17. }

  18. };

  19. //命令类

  20. class Command

  21. {

  22. public:

  23. virtual void execute(){}

  24. };

  25. //具体命令类

  26. class LigthOnCommand : public Command

  27. {

  28. public:

  29. LigthOnCommand(Light* lig):light(lig){}

  30. //execute方法

  31. void execute()

  32. {

  33. light->on();

  34. }

  35. private:

  36. Light* light;

  37. };

  38.  
  39. class LigthOffCommand : public Command

  40. {

  41. public:

  42. LigthOffCommand(Light* lig):light(lig){}

  43. void execute()

  44. {

  45. light->off();

  46. }

  47. private:

  48. Light* light;

  49. };

  50.  
  51. //遥控器类

  52. class RemoteControl

  53. {

  54. public:

  55. void setCommand(Command* command)

  56. {

  57. slot = command;

  58. }

  59. void buttonOn()

  60. {

  61. slot->execute();

  62. }

  63. private:

  64. Command* slot;

  65. };

  66. //客户代码

  67. int main()

  68. {

  69. RemoteControl lightOnControl;

  70. RemoteControl lightOffControl;

  71.  
  72. Command* onCommand = new LigthOnCommand(new Light());

  73. Command* offCommand = new LigthOffCommand(new Light());

  74.  
  75. lightOnControl.setCommand(onCommand);

  76. lightOffControl.setCommand(offCommand);

  77.  
  78. lightOnControl.buttonOn();

  79. lightOffControl.buttonOn();

  80.  
  81. return 0;

  82. }

执行结果:

Lighton !

Lightoff !

请按任意键继续. . .