常见设计模式设计及其实现–单例模式、工厂模式、观察者模式、装饰器模式
目录
前言
设计模式(Design pattern):是针对设计问题的通用解决方案。
是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性,也使代码编制真正工程化。
环境:vs2019
一、设计模式
1 设计模式6大设计原则
- 单一职责原则(Single Responsibility Principle,简称SRP):就一个类而言,应该仅有一个引起它变化的原因;即一个类只负责完成一个职责或者功能。
- 开放封闭原则(Open Close Principle,简称OCP):软件实体可扩展但不可修改;即面对需求,对程序的改动可通过增加代码来完成,但不可改动现有的代码。
- 里氏替换原则(Liskov Substitution Principle,简称LSP):一个软件实体如果使用的是一个基类,那么一定适用于其派生类;即在软件中,把基类替换成派生类,程序的行为并无变化。
- 依赖反转原则(Dependence Inversion Principle,简称DIP):高层模块不应该依赖底层模块,二者都该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象,即针对接口编程。
- 迪米特原则(Law of Demeter,简称LoD):若两个类不直接通信,那么这两个类就不应该发生直接的相互作用。若一个类需要调用另一个类的某个方法的话,可以通过第三个类转发此调用。
- 接口隔离原则(Interface Segregation Principle,简称ISP):每个接口在不存在派生类用不到却实现的方法,若不实现就得将接口拆分,使用多个隔离的接口。
更多细节请阅读:快速理解-设计模式六大原则
2 分类
- 创造型模式:单例模式、工厂模式、建造者模式、原型模式。
- 结构型模式:适配器模式、桥接模式、外观模式、组合模式、装饰模式、享元模式、代理模式。
- 行为型模式:责任链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法模式、访问者模式。
3 常见设计模式
- 单例模式:保证一个类仅有一个实例化对象,并提供一个访问它的全局访问点。
- 工厂模式:简单工厂模式、抽象工厂模式、工厂方法模式。
- 简单工厂模式:主要用于创建对象。用一个工厂来根据输入的条件产生不同的类,然后根据不同类的虚函数来得到不同的结果。
- 抽象工厂模式:定义了一个创建一系列相关或互相依赖的接口,而无需指定它们的具体类。
- 观察者模式:定义了一种一对多的关系,让多个观察者对象同时监听一个主题对象,主题对象发生变化时,或通知所有的观察者使它们能够更新自己。
- 装饰模式:动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成派生类更加灵活。
二、单例模式
单例模式:一种创建型设计模式,它确保一个类只有一个实例,并提供了一个全局访问点来访问该实例。
此模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。且这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
应用场景:
- 系统只需要一个实例化对象,或考虑资源消耗太大而之允许创建一个对象。
- 客户调用类的单个实例只允许使用一个公共访问点,除了该访问点之外不允许通过其他方式访问该实例,即共有的静态方法。
1 饿汉模式
在程序一开始就创建对象。例如,吃了饭就洗碗。
实现:
class SingleInstance1
{
public:
static SingleInstance1* GetInstance()
{
static SingleInstance1 s;
return &s;
}
~SingleInstance1() {}
private:
//涉及到创建对象的函数都进行私有化
//1.空构造
SingleInstance1()
{
cout << "SingleInstance1() 饿汉" << endl;
}
//2.拷贝构造
SingleInstance1(const SingleInstance1& s)
{}
//3.赋值运算符重载
SingleInstance1& operator=(const SingleInstance1& s)
{
return *this;
}
};
2 懒汉模式
当要用的时候再去创建对象。例如,要吃饭再洗碗。
实现:
//二、懒汉模式:线程安全需要进行加锁操作
//只有要用的时候才去实例化对象,即该单例类第一次被引用的时候将自己初始化
//如:写诗拷贝、晚绑定等
class SingleInstance2
{
public:
static SingleInstance2* GetInstance()
{
if (ins == nullptr)
{
_mutex.lock();
if (ins == nullptr)
ins = new SingleInstance2();
_mutex.unlock();
}
return ins;
}
~SingleInstance2() {}
static mutex _mutex; //互斥锁
private:
//涉及到创建对象的函数都进行私有化
SingleInstance2()
{
cout << "SingleInstance2() 懒汉" << endl;
}
SingleInstance2(const SingleInstance2& s) {}
SingleInstance2& operator=(const SingleInstance2& s)
{
return *this;
}
//静态成员
static SingleInstance2* ins;
};
//静态变量需要定义
SingleInstance2* SingleInstance2::ins = nullptr;
mutex SingleInstance2::_mutex;
三、工厂模式
工厂模式提供了一种将对象的实例化过程封装在工厂类中的方式,通过使用工厂模式,可以将对象的创建与使用代码分离,提供一种统一的接口来创建不同类型的对象。
1 简单工厂模式
就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建。实际上,简单工厂模式是由一个工厂类根据传入的参数来动态地决定应该创建哪一个产品类的实例,其中这些产品类继承自一个父类或接口。
#include<iostream>
#include<thread>
using namespace std;
//1.简单工厂模式:
//产品类(抽象类,不可实例化)
class Product
{
public:
Product(){}
virtual void show() = 0;
};
//产品A
class productA :public Product
{
public:
productA(){}
void show()
{
cout << "product A create" << endl;
}
~productA(){}
};
//产品B
class productB :public Product
{
public:
productB() {}
void show()
{
cout << "product B create" << endl;
}
~productB() {}
};
//工厂类
class simpleFactory
{
public:
simpleFactory(){}
Product* product(const string str)
{
if (str == "productA")
return new productA();
if (str == "productB")
return new productB();
return nullptr;
}
};
实际上,工厂模式目的就是代码解耦,若不采用工厂模式而要创建产品A、B,通常做法是采用switch…case语句,当产品变得更多时,语句就会变得格外的多,如此既会变得麻烦,同时也不符合设计模式中的开放封闭原则。
简单工厂模式基础下,进一步将工厂抽象处理啊,实现进一步的代码解耦。
2 抽象工厂模式
//2.抽象工厂模式:
//产品类(抽象类,不能实例化)
class PProduct
{
public:
PProduct(){}
virtual void show() = 0;
};
//产品A
class PProductA :public PProduct
{
public:
PProductA() {}
void show()
{
cout << "product A create" << endl;
}
};
//产品B
class PProductB :public PProduct
{
public:
PProductB() {}
void show()
{
cout << "product B create" << endl;
}
};
//工厂类(抽象类,不能实例化)
class FFactory
{
public:
virtual PProduct* createProduct() = 0;
};
//工厂类A,只生产产品A
class FactoryA :public FFactory
{
public:
PProduct* createProduct()
{
PProduct* pro = nullptr;
pro = new PProductA();
return pro;
}
};
//工厂类B,只生产产品B
class FactoryB :public FFactory
{
public:
PProduct* createProduct()
{
PProduct* pro = nullptr;
pro = new PProductB();
return pro;
}
};
四、观察者模式
观察者模式:定义一种一(被观察类)对多(观察类)的关系,让多个观察对象同时监听一个被观察对象,当被观察对象状态发生变化时,会通知所有的观察对象,使它们能够更新自己的状态。
存在的两种角色:
- 观察者:内部包含被观察对象,当被观察对象的状态发生变化时更新自己的状态,接受通知更新状态。
- 被观察者:内部包含了所有观察者对象,当状态发生变化时通知所有的观察者更新自己的状态,发送通知。
应用场景:
当一个对象的改变需要同时改变其他对象,且不知道具体有多少对象有待改变时的场景;一个抽象模型有两个方面,其中一方面依赖于另一方面,这时可用观察者模型将这两者封装在独立的对象中使它们各自独立地改变和复用。
观察者模式实现:
#include<iostream>
#include<string>
#include<list>
using namespace std;
class Subject;
//观察者基类(内部实例化了被观察的对象sub)
class Observer
{
protected:
string name;
Subject* sub;
public:
Observer(string name, Subject* sub)
{
this->name = name;
this->sub = sub;
}
virtual void update() = 0;
};
//观察者派生类
class PlayerObserver :public Observer
{
public:
PlayerObserver(string name, Subject* sub)
:Observer(name, sub)
{}
void update();
};
//观察者派生类
class NBAObserver :public Observer
{
public:
NBAObserver(string name, Subject* sub)
:Observer(name, sub)
{}
void update();
};
//被观察者基类(内部存放了所有的观察者对象,以便状态发生变化时,给观察者发送通知)
class Subject
{
protected:
list<Observer*> observers;
public:
string action; //被观察者的状态
public:
virtual void attach(Observer*) = 0;
virtual void detach(Observer*) = 0;
virtual void notify() = 0;
};
class Secretary :public Subject
{
public:
void attach(Observer* obe)
{
observers.push_back(obe);
}
void detach(Observer* obe)
{
auto it = observers.begin();
while (it != observers.end())
{
if ((*it) == obe)
{
observers.erase(it);
return;
}
++it;
}
}
void notify()
{
auto it = observers.begin();
while (it != observers.end())
{
(*it)->update();
++it;
}
}
};
void PlayerObserver::update()
{
cout << name << "收到消息:" << sub->action << endl;
if (sub->action == "老师来了")
{
cout << "停止玩耍,马上回到座位学习!" << endl;
}
}
void NBAObserver::update()
{
cout << name << "收到消息:" << sub->action << endl;
if (sub->action == "老师来了")
{
cout << "停止看球赛,马上回到座位学习!" << endl;
}
}
五、装饰器模式
装饰器模式:允许向一个现有的对象添加新的功能,同时又不改变其结构。
此类型的设计模式属于结构型模式,是作为现有类的一个包装,代码未改变原有类的内部结构,还为其增加了新的功能,即为装饰器模式的作用。
装饰器模式实现:
#include<iostream>
#include<list>
#include<memory>
using namespace std;
//抽象的构建类Transform->变形金刚
class Transform
{
public:
virtual void move() = 0;
};
//具体的构建类Car
class Car :public Transform
{
public:
Car()
{
cout << "变形金刚是一辆车" << endl;
}
void move()
{
cout << "在陆地上进行移动" << endl;
}
};
//抽象装饰类
class Changer :public Transform
{
public:
Changer(shared_ptr<Transform> trans)
{
this->transform = trans;
}
void move()
{
transform->move();
}
private:
shared_ptr<Transform> transform;
};
//具体装饰类Robot
class Robot :public Changer
{
public:
Robot(shared_ptr<Transform> trans)
:Changer(trans)
{
cout << "变成机器人" << endl;
}
void say()
{
cout << "然后说话" << endl;
}
};
//具体装饰类AirPlane
class AirPlane :public Changer
{
public:
AirPlane(shared_ptr<Transform> trans)
:Changer(trans)
{
cout << "变成飞机" << endl;
}
void say()
{
cout << "然后在天空飞翔" << endl;
}
};
make_shared:
make_shared函数的主要功能是在动态内存中分配一个对象并初始化它,返回指向此对象的shared_ptr,由于是通过shared_ptr管理内存,因此是一种安全分配和使用动态内存的方法。