看懂UML类图和时序图 - Graphic Design Patterns
目的
为什么会有设计模式,设计模式用来干什么?
单例模式
多线程下的单例模式
https://blog.csdn.net/m0_37872216/article/details/117406714
在GetInstance()对类进行实例化赋给静态成员变量时,需要考虑多线程安全问题,会重复实例化类,
解决办法:实例化过程加互斥锁,进阶且提高效率的话,就是两次判断s_instance是否为null,第一次是防止实例化后还要访问互斥量,第二次则是真正的互斥地将s_instance从无到有的过程。
如何保证一个类只能有实例?自己的话从哪个角度思考?
- 构造函数私有化,不让用户通过构造函数来更多地实例化。
一个类只有一个实例,这样的话,类和实例等价,就可以用static的相关性质,static修饰的都是属于类。
static的哪些作用可以用于这个单例模式回答自己的问题?
static修饰类的成员变量,在全局数据区分配内存,不在类声明或者类对象实例化分配内存,而是在类初始化时分配内存。且所有对象共用这一个静态成员变量,很好地契合单例模式。
- static修饰的类的成员变量,可以在类内进行访问?非静态成员函数可以任意访问静态成员函数和静态成员
- static修饰的类的成员函数也是属于类的,只能操作静态成员变量。不需要对类进行实例化就可以访问。 ```cpp /*
- 单例模式
- 一个类只能有一个实例化对象
- 2.要保证一个类只能有一个实例化对象,先要私有化构造函数,禁止外部实例化;随后用static静态成员指针保存对于该类第一个实例化的引用
- /
class CSingleton {
private:
static CSingleton m_instance;
CSingleton();
public:
static CSingleton* GetInstance() { //这里之所以要用static,是为了让外部能通过类名直接访问这个GetInstance()
if (m_instance == nullptr) {
} return m_instance; } }; /*m_instance = new CSingleton();
- /
class CSingleton {
private:
static CSingleton m_instance;
CSingleton();
public:
static CSingleton* GetInstance() { //这里之所以要用static,是为了让外部能通过类名直接访问这个GetInstance()
if (m_instance == nullptr) {
- 这个地方很重要,必须对静态成员变量在类外初始化 / CSingleton CSingleton::m_instance = nullptr;//静态变量类外初始化怎么初始化?初始化方式 类型 类名::静态成员名=初始值
int main() { CSingleton a1 = CSingleton::GetInstance(); CSingleton a2 = CSingleton::GetInstance(); //此时引用的是同一个m_instance
}
<a name="dGH32"></a>## 简单工厂模式<br />工厂类:根据**传入的参数不同创建不同的实例**,工厂类一般采用单例模式<br />对于不同的实例所对应的类之间的关系:有一个公共的抽象类父类。```cpp/** *******简单工厂模式************* 1.设计一个应用场景:一个计算的抽象父类,三个具体的"+"、"-"、"x"的计算类,一个工厂单例类,全局只有这个实例,根据传入的参数"+","-"来创建对应的计算类* 2.抽象父类和具体的计算类抽象父类: AbstractOp ,几个继承子类 ConcreteAdd , ConcreteMul, ConcreteSub。用来重写的抽象函数virtual int Calculate()=0; void Setx(int x){}; void Sety(int y){};*3. 工厂的单例模式设计Factory,类中的静态成员变量 static Factory* m_instance,类中获取实例的函数static Factory* Get_instance();类中构造具体的计算类的函数 AbstractOp* StructureCal2(string s);类中可以用静态成员函数创建具体的操作函数,static AbstractOp* StructureCal(string s);*4. 设计的测试案例*/#include<iostream>#include<string>using namespace std;class AbstractOp {public:int x;int y;virtual int Calculate() = 0;void Setx(int x1) {x= x1;return;};void Sety(int y1) {y = y1;return;};/** 成员变量初始化*/AbstractOp() : x(0), y(0) {};};class ConcreteAdd :public AbstractOp {virtual int Calculate() {return x + y;}};class ConcreteMul :public AbstractOp {virtual int Calculate() {return x*y;}};class ConcreteSub :public AbstractOp {virtual int Calculate() {return x - y;}};/** 工厂实例*/class Factory {static Factory* m_instance;Factory() {};public:static Factory* GetInstance() {if (m_instance == nullptr) {m_instance = new Factory();}return m_instance;}AbstractOp* StructureCal2(string s) {if (s == "+") {return new ConcreteAdd();}if (s == "-") {return new ConcreteSub();}if (s == "x") {return new ConcreteMul();}return nullptr;}static AbstractOp* StructureCal(string s) {if (s == "+") {return new ConcreteAdd();}if (s == "-") {return new ConcreteSub();}if (s == "x") {return new ConcreteMul();}return nullptr;}};Factory* Factory::m_instance = nullptr;int main() {Factory* fa = Factory::GetInstance();//方式一:通过单例模式下的工厂类实现(这种方式需要实例化一个类)AbstractOp* mul = fa->StructureCal2("x");mul->Setx(1);mul->Sety(2);cout << mul->Calculate()<<endl;//方式二:通过非实例化的类的静态成员函数实现创建(这种方式不需要实例化对象,直接用类即可实现)AbstractOp* add = Factory::StructureCal("+");add->Setx(1);add->Sety(2);cout << add->Calculate();return 0;}
工厂方法模式
和简单工厂的区别在于,工厂方法模式是抽象工厂不负责产品的实例化,针对每类具体的产品,从抽象工厂中派生出具体的工厂类来完成该产品。
好处:每新增一个产品,不用修改抽象工厂类,而是直接从抽象工厂类中派生出一个生产该产品的具体工厂类。
抽象工厂模式
解决工厂方法模式中,单一的具体工厂类只能生产一个产品的问题。
需求:具体工厂有海尔工厂、小天鹅工厂,海尔工厂里面可以生产海尔电视机、海尔空调,小天鹅工厂里面可以生产小天鹅电视机,小天鹅空调。
这里海尔工厂+小天鹅工厂可以抽象出一个抽象工厂类。海尔电视机+小天鹅电视机可以抽象出一个抽象电视机类,海尔空调+小天鹅空调可以抽象出一个抽象空调类。三类抽象模式。
装饰器模式-一个类要增加新的功能
问题:装饰器模式的具体应用场景是什么?问题的切入点
抽象基类是流类(read,seek,write),有几个具体的继承类,如文件流、网络流、内存流;如果对流还有加密和缓存需要,则要对每种流都继承出两个甚至多个子类,会造成每种流的相同功能代码冗余。
针对上述问题,一个可行的办法是,就加密而言,设计一个加密类继承抽象基类,通过把具体的继承类传入实现对具体的继承类进行加密功能。这样就
将一个类的实例化传到另一个新的类的实例化里面,同时这个新的类可以对原有类的方法进行补充。
装饰器模式和继承模式的区别:继承模式是基类和继承类,两者是继承关系;而装饰器模式是新类中包含旧类,再另外实现其他功能。装饰器模式更加灵活,装饰器模式更加适合大版本的迭代,而继承模式则适合小版本的迭代。
为什么这么说?
装饰器模式要干什么?
举例:
状态模式
不同的状态下有不同的行为,于是有抽象的状态基类和继承基类的不同的”高兴”、”悲伤”状态子类和对应的行为。
一个对象根据不同状态执行不同的行为,这个对象对应的类就是环境类,也即”人”。在这个类里面,可以改变状态,并且根据所改变后的状态在做事时方法不同。
策略模式
根据传入的不同执行策略来完成不同的行为。比如C++的sort函数,根据传入的cmp的比较策略来决定的是按照从大到小还是从小到大排序。
代理模式
为对象A提供一种代理,代理类管理其他对象对于对象A的访问。
观察者模式
多个观察者监视一个对象,当这个对象的状态发生改变时,对象会去通知所有的观察者。
