面对对象中有哪些设计原则
开闭原则
里氏替换原则
迪米特原则
依赖导致原则
** 举例解释**
自动驾驶系统公司是高层,汽车生产厂商为低层,它们不应该互相依赖,一方变动另一方也会跟着变动;而应该抽象一个自动驾驶行业标准,高层和低层都依赖它;这样以来就解耦了两方的变动;自动驾驶系统、汽车生产厂商都是具体实现,它们应该都依赖自动驾驶行业标准(抽象)。
多线程环境下单例模式
单例单线程模式
- 保证一个类仅有一个实例:使用静态成员变量形式来实现。
- 提供该实例的全局访问点:使用静态的成员函数来实现。
- 保证申请在堆区的
Singleton()
能够被释合理的释放掉:使用c++中的库函数atextit()
,atexit函数详解参考。并需手动实现析构函数。 - 为了实现只能通过
GetInstance()
函数来实现对象的创建需要对外屏蔽构造函数、赋值操作、拷贝构造函数。 - 静态成员函数只能访问静态成员变量和静态成员函数。
- 静态成员函数没有
this
指针,不能调用成员函数,可参考static、const关键字。
//Singleton
#include <iostream>
class Singleton {
public:
static Singleton* GetInstance() {
if (_instance == nullptr) {
_instance = new Singleton();
std::atexit(Destructor); //登记函数
}
return _instance;
}
private:
static void Destructor() { //实现析构
if (_instance != nullptr) {
delete _instance;
_instance = nullptr;
}
}
Singleton() {};
~Singleton() {};
Singleton(const Singleton &clone) {}; //拷贝构造函数
Singleton &operator= (const Singleton &) {}; //赋值操作
static Singleton *_instance; //一个类只有一个实例
};
Singleton* Singleton::_instance = nullptr; //静态变量,类内声明类外初始化
多线程环境下单例模式—只加锁
加锁
只保证了临界资源只有一个线程访问。
//Singleton_thread 加锁
#include <iostream>
#include <mutex>
class Singleton {
public:
static Singleton* GetInstance() {
//std::lock_guard<std::mutex> lock(_mutex); //该位置锁的力度过大
if (_instance == nullptr) { //第一次_instance没有值
std::lock_guard<std::mutex> lock(_mutex);
if (_instance == nullptr) { //其他情况下_instance有值
_instance = new Singleton(); //多线程环境下编译器和CPU会对程序进行优化
std::atexit(Destructor);
}
}
return _instance;
}
private:
static void Destructor() { //实现析构
if (_instance != nullptr) {
delete _instance;
_instance = nullptr;
}
}
Singleton() {};
~Singleton() {};
Singleton(const Singleton &clone) {}; //拷贝构造函数
Singleton &operator= (const Singleton &) {}; //赋值操作
static Singleton *_instance;
static std::mutex _mutex;
};
Singleton* Singleton::_instance = nullptr; //静态变量,类内声明类外初始化
std::mutex Singleton::_mutex;
多线程环境下单例模式—加锁+原子操作
- 多线程环境下编译器会对程序进行优化,导致指令执行顺序发生变化。
new
操作符执行了哪些操作:
1) 分配内存;
2)调用构造函数 (比较耗时);
3)返回指针,赋值运算符。
编译器优化后执行顺序可能为:1 3 2。就会出现内存还没有进行构造就进行了返回。即_instance
不为空,但是_instaned
没有经过构造函数初始化其内存,当使用到的时候就会出现错误。利用原子变量来避免这个现象。
//Singleton_atomic
#include <iostream>
#include <mutex>
#include <atomic>
class Singleton {
public:
static Singleton* GetInstance() {
Singleton* tmp = _instance.load(std::memory_order_relaxed); //保证tmp原子性
std::atomic_thread_fence(std::memory_order_acquire); //内存屏障,不让tmp优化到下面
//std::lock_guard<std::mutex> lock(_mutex); //该位置锁的力度过大
if (tmp == nullptr) { //第一次_instance没有值
std::lock_guard<std::mutex> lock(_mutex);
tmp = _instance.load(std::memory_order_relaxed);
if (tmp == nullptr) { //其他情况下_instance有值
tmp = new Singleton(); //多线程环境下编译器和CPU会对程序进行优化
std::atomic_thread_fence(std::memory_order_release); //不让store优化到上面去
_instance.store(tmp, std::memory_order_relaxed); //将tmp写回原子变量_instance中
std::atexit(Destructor);
}
}
return tmp;
}
private:
static void Destructor() { //实现析构
Singleton* tmp = _instance.load(std::memory_order_relaxed);
if (tmp != nullptr) {
delete _instance;
tmp = nullptr;
_instance.store(tmp, std::memory_order_relaxed);
}
}
Singleton() {};
~Singleton() {};
Singleton(const Singleton &clone) {}; //拷贝构造函数
Singleton &operator= (const Singleton &) {}; //赋值操作
static std::atomic<Singleton*> _instance;
static std::mutex _mutex;
};
std::atomic<Singleton*> Singleton::_instance; //静态变量,类内声明类外初始化
std::mutex Singleton::_mutex;
工厂模式
工厂模式
// 实现导出数据的接口, 导出数据的格式包含 xml,json,文本格式txt 后面可能扩展excel格式csv
//factory
#include <string>
// 实现导出数据的接口, 导出数据的格式包含 xml,json,文本格式txt 后面可能扩展excel格式csv
class IExport {
public:
virtual bool Export(const std::string &data) = 0;
virtual ~IExport(){}
};
class ExportXml : public IExport {
public:
virtual bool Export(const std::string &data) {
return true;
}
};
class ExportJson : public IExport {
public:
virtual bool Export(const std::string &data) {
return true;
}
};
class ExportTxt : public IExport {
public:
virtual bool Export(const std::string &data) {
return true;
}
};
class ExportCSV : public IExport {
public:
virtual bool Export(const std::string &data) {
return true;
}
};
class IExportFactory {
public:
IExportFactory() {
_export = nullptr;
}
virtual ~IExportFactory() {
if (_export) {
delete _export;
_export = nullptr;
}
}
bool Export(const std::string &data) {
if (_export == nullptr) {
_export = NewExport();
}
return _export->Export(data);
}
protected:
virtual IExport * NewExport(/* ... */) = 0;
private:
IExport* _export;
};
class ExportXmlFactory : public IExportFactory {
protected:
virtual IExport * NewExport(/* ... */) {
// 可能有其它操作,或者许多参数
IExport * temp = new ExportXml();
// 可能之后有什么操作
return temp;
}
};
class ExportJsonFactory : public IExportFactory {
protected:
virtual IExport * NewExport(/* ... */) {
// 可能有其它操作,或者许多参数
IExport * temp = new ExportJson;
// 可能之后有什么操作
return temp;
}
};
class ExportTxtFactory : public IExportFactory {
protected:
IExport * NewExport(/* ... */) {
// 可能有其它操作,或者许多参数
IExport * temp = new ExportTxt;
// 可能之后有什么操作
return temp;
}
};
class ExportCSVFactory : public IExportFactory {
protected:
virtual IExport * NewExport(/* ... */) {
// 可能有其它操作,或者许多参数
IExport * temp = new ExportCSV;
// 可能之后有什么操作
return temp;
}
};
int main () {
IExportFactory *factory = new ExportTxtFactory();
factory->Export("hello world");
return 0;
}
抽象工厂
导出功能(
IExport
)、导入功能(IImport
),同一个格式的导入和导出是相关联的,我们通过一个接口去封装这个关联性,这里用IDataApiFactory
来实现。
#include <string>
// 实现导出数据的接口, 导出数据的格式包含 xml,json,文本格式txt 后面可能扩展excel格式csv
class IExport {
public:
virtual bool Export(const std::string &data) = 0;
virtual ~IExport(){}
};
class ExportXml : public IExport {
public:
virtual bool Export(const std::string &data) {
return true;
}
};
class ExportJson : public IExport {
public:
virtual bool Export(const std::string &data) {
return true;
}
};
class ExportTxt : public IExport {
public:
virtual bool Export(const std::string &data) {
return true;
}
};
class ExportCSV : public IExport {
public:
virtual bool Export(const std::string &data) {
return true;
}
};
class IImport {
public:
virtual bool Import(const std::string &data) = 0;
virtual ~IImport(){}
};
class ImportXml : public IImport {
public:
virtual bool Import(const std::string &data) {
return true;
}
};
class ImportJson : public IImport {
public:
virtual bool Import(const std::string &data) {
return true;
}
};
class ImportTxt : public IImport {
public:
virtual bool Import(const std::string &data) {
return true;
}
};
class ImportCSV : public IImport {
public:
virtual bool Import(const std::string &data) {
// ....
return true;
}
};
class IDataApiFactory {
public:
IDataApiFactory() {
_export = nullptr;
_import = nullptr;
}
virtual ~IDataApiFactory() {
if (_export) {
delete _export;
_export = nullptr;
}
if (_import) {
delete _import;
_import = nullptr;
}
}
bool Export(const std::string &data) {
if (_export == nullptr) {
_export = NewExport();
}
return _export->Export(data);
}
bool Import(const std::string &data) {
if (_import == nullptr) {
_import = NewImport();
}
return _import->Import(data);
}
protected:
virtual IExport * NewExport(/* ... */) = 0;
virtual IImport * NewImport(/* ... */) = 0;
private:
IExport *_export;
IImport *_import;
};
class XmlApiFactory : public IDataApiFactory {
protected:
virtual IExport * NewExport(/* ... */) {
// 可能有其它操作,或者许多参数
IExport * temp = new ExportXml;
// 可能之后有什么操作
return temp;
}
virtual IImport * NewImport(/* ... */) {
// 可能有其它操作,或者许多参数
IImport * temp = new ImportXml;
// 可能之后有什么操作
return temp;
}
};
class JsonApiFactory : public IDataApiFactory {
protected:
virtual IExport * NewExport(/* ... */) {
// 可能有其它操作,或者许多参数
IExport * temp = new ExportJson;
// 可能之后有什么操作
return temp;
}
virtual IImport * NewImport(/* ... */) {
// 可能有其它操作,或者许多参数
IImport * temp = new ImportJson;
// 可能之后有什么操作
return temp;
}
};
class TxtApiFactory : public IDataApiFactory {
protected:
virtual IExport * NewExport(/* ... */) {
// 可能有其它操作,或者许多参数
IExport * temp = new ExportTxt;
// 可能之后有什么操作
return temp;
}
virtual IImport * NewImport(/* ... */) {
// 可能有其它操作,或者许多参数
IImport * temp = new ImportTxt;
// 可能之后有什么操作
return temp;
}
};
class CSVApiFactory : public IDataApiFactory {
protected:
virtual IExport * NewExport(/* ... */) {
// 可能有其它操作,或者许多参数
IExport * temp = new ExportCSV;
// 可能之后有什么操作
return temp;
}
virtual IImport * NewImport(/* ... */) {
// 可能有其它操作,或者许多参数
IImport * temp = new ImportCSV;
// 可能之后有什么操作
return temp;
}
};
int main () {
IDataApiFactory *factory = new CSVApiFactory();
factory->Import("hello world");
factory->Export("hello world");
return 0;
}
直通通道:设计模式总结(二)
充电站
推荐一个零声学院免费公开课程,个人觉得老师讲得不错,分享给大家:Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK等技术内容,立即学习