看懂UML类图和时序图 - Graphic Design Patterns

目的

为什么会有设计模式,设计模式用来干什么?

项目设计实现的框架,解决特定问题。

单例模式

多线程下的单例模式

https://blog.csdn.net/m0_37872216/article/details/117406714
在GetInstance()对类进行实例化赋给静态成员变量时,需要考虑多线程安全问题,会重复实例化类,
解决办法:实例化过程加互斥锁,进阶且提高效率的话,就是两次判断s_instance是否为null,第一次是防止实例化后还要访问互斥量,第二次则是真正的互斥地将s_instance从无到有的过程。

如何保证一个类只能有实例?自己的话从哪个角度思考?

  1. 构造函数私有化,不让用户通过构造函数来更多地实例化。
  2. 一个类只有一个实例,这样的话,类和实例等价,就可以用static的相关性质,static修饰的都是属于类。

    static的哪些作用可以用于这个单例模式回答自己的问题?

    Arkin:C/C++ 中的static关键字

  3. static修饰类的成员变量,在全局数据区分配内存,不在类声明或者类对象实例化分配内存,而是在类初始化时分配内存。且所有对象共用这一个静态成员变量,很好地契合单例模式。

  4. static修饰的类的成员变量,可以在类内进行访问?非静态成员函数可以任意访问静态成员函数和静态成员
  5. static修饰的类的成员函数也是属于类的,只能操作静态成员变量。不需要对类进行实例化就可以访问。 ```cpp /*
  • 单例模式
    1. 一个类只能有一个实例化对象
  • 2.要保证一个类只能有一个实例化对象,先要私有化构造函数,禁止外部实例化;随后用static静态成员指针保存对于该类第一个实例化的引用
    1. / class CSingleton { private: static CSingleton m_instance; CSingleton(); public: static CSingleton* GetInstance() { //这里之所以要用static,是为了让外部能通过类名直接访问这个GetInstance() if (m_instance == nullptr) {
      1. m_instance = new CSingleton();
      } return m_instance; } }; /*
  • 这个地方很重要,必须对静态成员变量在类外初始化 / CSingleton CSingleton::m_instance = nullptr;//静态变量类外初始化怎么初始化?初始化方式 类型 类名::静态成员名=初始值

int main() { CSingleton a1 = CSingleton::GetInstance(); CSingleton a2 = CSingleton::GetInstance(); //此时引用的是同一个m_instance

}

  1. <a name="dGH32"></a>
  2. ## 简单工厂模式
  3. ![image.png](https://cdn.nlark.com/yuque/0/2022/png/2449982/1651402228443-7a4daa4e-cda3-473a-88a0-ff0899de9278.png#clientId=u1d71a1cc-a657-4&crop=0&crop=0&crop=1&crop=1&from=paste&id=u2431a2ee&margin=%5Bobject%20Object%5D&name=image.png&originHeight=574&originWidth=720&originalType=url&ratio=1&rotation=0&showTitle=false&size=147190&status=done&style=none&taskId=u1943848d-1e7b-4bcb-a47c-56adb6527eb&title=)<br />工厂类:根据**传入的参数不同创建不同的实例**,工厂类一般采用单例模式<br />对于不同的实例所对应的类之间的关系:有一个公共的抽象类父类。
  4. ```cpp
  5. /*
  6. * *******简单工厂模式************
  7. * 1.设计一个应用场景:一个计算的抽象父类,三个具体的"+"、"-"、"x"的计算类,
  8. 一个工厂单例类,全局只有这个实例,根据传入的参数"+","-"来创建对应的计算类
  9. * 2.抽象父类和具体的计算类
  10. 抽象父类: AbstractOp ,几个继承子类 ConcreteAdd , ConcreteMul, ConcreteSub。
  11. 用来重写的抽象函数virtual int Calculate()=0; void Setx(int x){}; void Sety(int y){};
  12. *3. 工厂的单例模式设计
  13. Factory,类中的静态成员变量 static Factory* m_instance,类中获取实例的函数static Factory* Get_instance();
  14. 类中构造具体的计算类的函数 AbstractOp* StructureCal2(string s);
  15. 类中可以用静态成员函数创建具体的操作函数,static AbstractOp* StructureCal(string s);
  16. *4. 设计的测试案例
  17. */
  18. #include<iostream>
  19. #include<string>
  20. using namespace std;
  21. class AbstractOp {
  22. public:
  23. int x;
  24. int y;
  25. virtual int Calculate() = 0;
  26. void Setx(int x1) {
  27. x= x1;
  28. return;
  29. };
  30. void Sety(int y1) {
  31. y = y1;
  32. return;
  33. };
  34. /*
  35. * 成员变量初始化
  36. */
  37. AbstractOp() : x(0), y(0) {};
  38. };
  39. class ConcreteAdd :public AbstractOp {
  40. virtual int Calculate() {
  41. return x + y;
  42. }
  43. };
  44. class ConcreteMul :public AbstractOp {
  45. virtual int Calculate() {
  46. return x*y;
  47. }
  48. };
  49. class ConcreteSub :public AbstractOp {
  50. virtual int Calculate() {
  51. return x - y;
  52. }
  53. };
  54. /*
  55. * 工厂实例
  56. */
  57. class Factory {
  58. static Factory* m_instance;
  59. Factory() {};
  60. public:
  61. static Factory* GetInstance() {
  62. if (m_instance == nullptr) {
  63. m_instance = new Factory();
  64. }
  65. return m_instance;
  66. }
  67. AbstractOp* StructureCal2(string s) {
  68. if (s == "+") {
  69. return new ConcreteAdd();
  70. }
  71. if (s == "-") {
  72. return new ConcreteSub();
  73. }
  74. if (s == "x") {
  75. return new ConcreteMul();
  76. }
  77. return nullptr;
  78. }
  79. static AbstractOp* StructureCal(string s) {
  80. if (s == "+") {
  81. return new ConcreteAdd();
  82. }
  83. if (s == "-") {
  84. return new ConcreteSub();
  85. }
  86. if (s == "x") {
  87. return new ConcreteMul();
  88. }
  89. return nullptr;
  90. }
  91. };
  92. Factory* Factory::m_instance = nullptr;
  93. int main() {
  94. Factory* fa = Factory::GetInstance();
  95. //方式一:通过单例模式下的工厂类实现(这种方式需要实例化一个类)
  96. AbstractOp* mul = fa->StructureCal2("x");
  97. mul->Setx(1);
  98. mul->Sety(2);
  99. cout << mul->Calculate()<<endl;
  100. //方式二:通过非实例化的类的静态成员函数实现创建(这种方式不需要实例化对象,直接用类即可实现)
  101. AbstractOp* add = Factory::StructureCal("+");
  102. add->Setx(1);
  103. add->Sety(2);
  104. cout << add->Calculate();
  105. return 0;
  106. }

工厂方法模式

和简单工厂的区别在于,工厂方法模式是抽象工厂不负责产品的实例化,针对每类具体的产品,从抽象工厂中派生出具体的工厂类来完成该产品。
好处:每新增一个产品,不用修改抽象工厂类,而是直接从抽象工厂类中派生出一个生产该产品的具体工厂类
image.png

抽象工厂模式

解决工厂方法模式中,单一的具体工厂类只能生产一个产品的问题。
需求:具体工厂有海尔工厂、小天鹅工厂,海尔工厂里面可以生产海尔电视机、海尔空调,小天鹅工厂里面可以生产小天鹅电视机,小天鹅空调。
这里海尔工厂+小天鹅工厂可以抽象出一个抽象工厂类。海尔电视机+小天鹅电视机可以抽象出一个抽象电视机类,海尔空调+小天鹅空调可以抽象出一个抽象空调类。三类抽象模式。
image.png

装饰器模式-一个类要增加新的功能

问题:装饰器模式的具体应用场景是什么?问题的切入点
抽象基类是流类(read,seek,write),有几个具体的继承类,如文件流、网络流、内存流;如果对流还有加密和缓存需要,则要对每种流都继承出两个甚至多个子类,会造成每种流的相同功能代码冗余。
针对上述问题,一个可行的办法是,就加密而言,设计一个加密类继承抽象基类,通过把具体的继承类传入实现对具体的继承类进行加密功能。这样就

将一个类的实例化传到另一个新的类的实例化里面,同时这个新的类可以对原有类的方法进行补充。
装饰器模式和继承模式的区别:继承模式是基类和继承类,两者是继承关系;而装饰器模式是新类中包含旧类,再另外实现其他功能。装饰器模式更加灵活,装饰器模式更加适合大版本的迭代,而继承模式则适合小版本的迭代
为什么这么说?
装饰器模式要干什么?
举例:

状态模式

不同的状态下有不同的行为,于是有抽象的状态基类和继承基类的不同的”高兴”、”悲伤”状态子类和对应的行为。
一个对象根据不同状态执行不同的行为,这个对象对应的类就是环境类,也即”人”。在这个类里面,可以改变状态,并且根据所改变后的状态在做事时方法不同。

策略模式

根据传入的不同执行策略来完成不同的行为。比如C++的sort函数,根据传入的cmp的比较策略来决定的是按照从大到小还是从小到大排序。

代理模式

为对象A提供一种代理,代理类管理其他对象对于对象A的访问。

观察者模式

多个观察者监视一个对象,当这个对象的状态发生改变时,对象会去通知所有的观察者。