核心思想:分而治之,将大问题分解为多个小问题,将复杂问题分解为多个简单的问题。
核心思想:从高层次角度讲,人们处理复杂性有一个通用的技术,及抽象。由于不能掌握全部的复杂对象,选择护士他的非本质细节,而去处理泛化和理想化的对象模型。
总结来说就是,复用最好的代码就是复用性高。
对象的概念:
依赖倒置原则(DIP):
开放封闭原则(OCP):
单一职责原则(SRP):
Liskov替换原则(LSP):
接口隔离原则(ISP):
优先使用对象组合,而不是类继承
封装变化点:
针对接口与编码,而不是针对实现编程:产业强盛的标志
从目的来看:
从范围来看:
工厂模式:主要是封装了对象的创建。
简单工厂(Simple Factory):
优点:
缺点:
工厂方法(Factory Method):
优点:
缺点:
抽象工厂(Abstact Factory)
优点:
这里使用了一个汽车生产的工厂示例,列举了简单工厂和工厂方法,并使用智能指针进行对象空间优化回收。
#include
#include
#include
using namespace std;
class Car
{
public:
Car(string name):_name(name){}
virtual void show() = 0; //定义纯虚函数,子类必须实现
protected:
string _name;
private:
};
class BMW:public Car
{
public:
// 使用Car(name)类似于_name(name),还是用了Car的_name,
// 子类继承父类的构造函数可以参考 https://blog.csdn.net/aquapisces/article/details/104371658
BMW(string name) : Car(name){};
void show()
{
cout << "获取了一辆宝马汽车" << _name << endl;
}
protected :
private:
};
class Audi : public Car
{
public:
// 使用Car(name)类似于_name(name),还是用了Car的_name,
// 子类继承父类的构造函数可以参考 https://blog.csdn.net/aquapisces/article/details/104371658
Audi(string name) : Car(name){};
void show()
{
cout << "获取了一辆奥迪汽车" << _name << endl;
}
protected:
private:
};
// ------------------------------------------------------------------------------------------
/*
简单工厂存在以下问题:开闭原则,新增一个汽车则需要修改很多代码;BMW类和Audi类都在一个工厂里面生产
*/
enum CarType
{
bmw,audi
};
class SimpleFactory
{
public:
Car* createCar(CarType ct)
{
switch (ct)
{
case bmw:
return new BMW("X1");
case audi:
return new Audi("A6");
default:
cout << "传入工厂的参数不正确:" << ct << endl;
break;
}
return nullptr;
}
};
// ------------------------------------------------------------------------------------------
/*
工厂方法
*/
class Factory
{
public:
virtual Car* createCar(string name) = 0;
};
class BMWFactory:public Factory
{
public:
Car* createCar(string name)
{
return new BMW(name);
}
};
class AudiFactory : public Factory
{
public:
Car *createCar(string name)
{
return new Audi(name);
}
};
// ------------------------------------------------------------------------------------------
int main()
{
// unique_ptr无法进行普通拷贝构造和赋值unique_ptr p1=new BMW("X1");是错误的
// 最原始的对象产生
unique_ptr<Car> p1(new BMW("X1"));
unique_ptr<Car> p2(new Audi("A6"));
// 简单工厂
// unique_ptr factory(new SimpleFactory());
// unique_ptr p1(factory->createCar(bmw));
// unique_ptr p2(factory->createCar(audi));
// 工厂方法
// unique_ptr bmwFactory(new BMWFactory);
// unique_ptr audiFactory(new AudiFactory);
// unique_ptr p1(bmwFactory->createCar("X6"));
// unique_ptr p2(audiFactory->createCar("A8"));
p1->show();
p2->show();
return 0;
}
上一节中的工厂方法会存在一个问题,在定义了一个Factory
抽象类后,每一个类将对应一个类的工厂,如BWM->BMWFactory
,Audi->AudiFactory
,这样会导致一个问题,在生产一类产品时,如手机充电器和充电线,那么就又需要两个工厂来实现,所以这样就会导致工厂冗余。所以,提出了抽象工厂来解决这个问题,这里以汽车的生产部件为例进行说明:
#include
#include
#include
using namespace std;
class Car
{
public:
Car(string name):_name(name){}
virtual void show() = 0; //定义纯虚函数,子类必须实现
protected:
string _name;
private:
};
class BMW:public Car
{
public:
// 使用Car(name)类似于_name(name),还是用了Car的_name,
// 子类继承父类的构造函数可以参考 https://blog.csdn.net/aquapisces/article/details/104371658
BMW(string name) : Car(name){};
void show()
{
cout << "获取了一辆宝马汽车" << _name << endl;
}
protected :
private:
};
class Audi : public Car
{
public:
// 使用Car(name)类似于_name(name),还是用了Car的_name,
// 子类继承父类的构造函数可以参考 https://blog.csdn.net/aquapisces/article/details/104371658
Audi(string name) : Car(name){};
void show()
{
cout << "获取了一辆奥迪汽车" << _name << endl;
}
protected:
private:
};
class Light
{
public:
virtual void show() = 0;
};
class BMWLight:public Light
{
public:
void show()
{
cout << "BMW light!" << endl;
}
};
class AudiLight : public Light
{
public:
void show()
{
cout << "Audi light!" << endl;
}
};
/*
抽象工厂,对一组关联关系的产品簇提供产品对象的统一创建。
有点类似于工厂方法
*/
class AbstractFactory
{
public:
virtual Car *createCar(string name) = 0;
virtual Light *createCarLight() = 0;
};
class BMWFactory : public AbstractFactory
{
public:
Car *createCar(string name)
{
return new BMW(name);
}
Light *createCarLight()
{
return new BMWLight();
}
};
class AudiFactory : public AbstractFactory
{
public:
Car *createCar(string name)
{
return new Audi(name);
}
Light *createCarLight()
{
return new AudiLight();
}
};
int main()
{
// 抽象工厂方法
unique_ptr<AbstractFactory> bmwFactory(new BMWFactory);
unique_ptr<AbstractFactory> audiFactory(new AudiFactory);
unique_ptr<Car> p1(bmwFactory->createCar("X6"));
unique_ptr<Car> p2(audiFactory->createCar("A8"));
unique_ptr<Light> l1(bmwFactory->createCarLight());
unique_ptr<Light> l2(audiFactory->createCarLight());
p1->show();
p2->show();
l1->show();
l2->show();
return 0;
}
代理(proxy)模式:通过代理类,来控制实际对象的访问权限。其实也就是定义一个虚基类,子类继承虚基类实现不同级别对象的实现,可以看以下类似代码:
#include
#include
#include
using namespace std;
class VideoSite
{
public:
virtual void freeMovie() = 0;
virtual void vipMovie() = 0;
virtual void ticketMovie() = 0;
};
class FixBugVideoSite:public VideoSite
{
// 不同的用户的访问权限可能不够,所以下面三个函数有些对象不能调用
void freeMovie()
{
cout << "观看免费电影" << endl;
}
void vipMovie()
{
cout << "观看vip电影" << endl;
}
void ticketMovie()
{
cout << "观看电影券电影" << endl;
}
};
// 代理类,用于代理FixBugVideoSite
class FreeVideoSiteProxy:public VideoSite
{
public:
FreeVideoSiteProxy()
{
pVideo = new FixBugVideoSite();
}
~FreeVideoSiteProxy()
{
if(pVideo!=nullptr)
{
delete pVideo;
}
pVideo = nullptr;
}
void freeMovie()
{
pVideo->freeMovie();
}
void vipMovie()
{
cout << "您目前只是普通用户,需要升级成vip才能观看vip电影" << endl;
}
void ticketMovie()
{
cout << "您目前只是普通用户,需要购买电影券才能观看电影" << endl;
}
private:
VideoSite *pVideo;
};
class VipVideoSiteProxy : public VideoSite
{
public:
VipVideoSiteProxy()
{
pVideo = new FixBugVideoSite();
}
~VipVideoSiteProxy()
{
if (pVideo != nullptr)
{
delete pVideo;
}
pVideo = nullptr;
}
void freeMovie()
{
pVideo->freeMovie();
}
void vipMovie()
{
pVideo->vipMovie();
}
void ticketMovie()
{
cout << "您目前只是普通用户,需要购买电影券才能观看电影" << endl;
}
private:
VideoSite *pVideo;
};
int main()
{
// unique_ptr p1(new FreeVideoSiteProxy());
unique_ptr<VideoSite> p1(new VipVideoSiteProxy());
p1->freeMovie();
p1->vipMovie();
p1->ticketMovie();
return 0;
}
行为型模式:主要关注的是对象之间的通信。
以观察者-监听者模式(发布-订阅模式)设计模式:主要关注的是对象的一对多的关系,也就是多个对象都依赖一个对象,当该对象的状态发生改变时,其他对象都能够结束到相应的通知。
ps:一组数据改变(数据对象)->通过这一组数据->曲线图(对象1)/柱状图(对象2)/圆饼图(对象3)。当数据对象改变时,对象1、对象2、对象3应该及时的收到相应的通知。
#include
#include
#include
#include
using namespace std;
/**
观察者模式/订阅模式:当一个对象发生改变时,会通知其他对象去处理对象的事件。
*/
class Observer
{
public:
virtual void handle(int msgid) = 0;
};
class Observer1:public Observer
{
void handle(int msgid)
{
switch (msgid)
{
case 1:
cout << "observer1 recv 1 msg." << endl;
break;
case 2:
cout << "observer1 recv 2 msg." << endl;
break;
default:
cout << "observer1 recv unknow msg." << endl;
break;
}
}
};
class Observer2 : public Observer
{
void handle(int msgid)
{
switch (msgid)
{
case 3:
cout << "observer2 recv 3 msg." << endl;
break;
case 2:
cout << "observer2 recv 2 msg." << endl;
break;
default:
cout << "observer2 recv unknow msg." << endl;
break;
}
}
};
class Observer3 : public Observer
{
void handle(int msgid)
{
switch (msgid)
{
case 1:
cout << "observer3 recv 1 msg." << endl;
break;
case 3:
cout << "observer3 recv 3 msg." << endl;
break;
default:
cout << "observer3 recv unknow msg." << endl;
break;
}
}
};
class Subjects
{
public:
// 给主题添加观察者对象
void addObserver(Observer* obser,int msgid)
{
// 和下面的操作一致,如果存在msgid为key的情况就直接插入,没有就创建一个并插入
_submap[msgid].push_back(obser);
/**
// 查找map中是否存在有key为msgid的值
auto it = _submap.find(msgid);
if(it != _submap.end())
{
it->second.push_back(obser);
}
else
{
list olist;
olist.push_back(obser);
_submap.insert(make_pair(msgid, olist));
}
*/
}
// 主题检测发生改变,通知相应的观察者对象处理事件
void dispatch(int msg)
{
auto it = _submap.find(msg);
if (it != _submap.end())
{
for(Observer* pObser:it->second)
{
pObser->handle(msg);
}
}
}
private:
unordered_map<int, list<Observer *>> _submap;
};
int main()
{
Subjects sub;
Observer *p1 = new Observer1();
Observer *p2 = new Observer2();
Observer *p3 = new Observer3();
sub.addObserver(p1, 1);
sub.addObserver(p2, 3);
sub.addObserver(p3, 1);
sub.addObserver(p3, 2);
sub.addObserver(p1, 3);
sub.dispatch(2);
return 0;
}
适配器模式:让不兼容的接口可以在一起工作。
下方使用C++实现了一个电脑播放投影视频的例子,电脑仅仅支持VGA接口,如何实现HDMI接口转化成VGA来适配电脑使用。也就是如何实现一个VGA和HEMI类的转化接口。
#include
#include
using namespace std;
class VGA
{
public:
virtual void play() = 0;
};
class TV01:public VGA
{
public:
void play() { cout << "通过VGA接口连接投影仪,进行视频播放!" << endl; }
};
class HDMI
{
public:
virtual void play() = 0;
};
class TV02 : public HDMI
{
public:
void play() { cout << "通过HDMI接口连接投影仪,进行视频播放!" << endl; }
};
// 一定要继承原来的类
class VGA2HDMIAdapter:public VGA
{
public:
VGA2HDMIAdapter(HDMI* p):phdmi(p){}
void play() { phdmi->play(); }
private:
HDMI *phdmi;
};
class Computer
{
public:
// 由于电脑只支持VGA接口,所以该方法的参数也只支持VGA接口的指针/引用
void playVideo(VGA *pVGA) { pVGA->play(); }
};
int main()
{
// HDMI和VGA无法进行互相转化,电脑如何使用HDMI的play方法?
/*
1、换一个支持HDMI的电脑,也就是对Computer类进行重构,叫做代码重构。
2、使用一个适配器(转化头),把VGA类转化为HDMI类,叫做添加适配器类。
*/
Computer computer;
computer.playVideo(new TV01());
computer.playVideo(new VGA2HDMIAdapter(new TV02()));
return 0;
}
装饰器(decorate)模式和代理模式类似。代理模式也就是定义委托类和代理类继承抽象类,并重写函数方法,通过在代理类中使用委托类的对象调用不同级别代理的方法访问。
装饰器主要是增加现有类的功能,但是添加现有类的一个方法还有一个方法,就是新建一个子类。如果每次新建一个功能都需要新建一个子类的话,那么代码中就会有很多的子类被添加进来。
以下实现了一个汽车装饰类的代码实现:
#include
#include
using namespace std;
class Car
{
public:
virtual void show() = 0;
};
class BMW : public Car
{
public:
void show() { cout << "这是一辆宝马汽车!有基本配置"; }
};
class Audi : public Car
{
public:
void show() { cout << "这是一辆奥迪汽车!有基本配置"; }
};
class Benc : public Car
{
public:
void show() { cout << "这是一辆奔驰汽车!有基本配置"; }
};
// 装饰器
class CarDecorator01 : public Car
{
public:
CarDecorator01(Car *p) : pCar(p){};
void show()
{
pCar->show();
cout << ",辅助驾驶";
}
private:
Car *pCar;
};
class CarDecorator02 : public Car
{
public:
CarDecorator02(Car *p) : pCar(p){};
void show()
{
pCar->show();
cout << ",自动校正";
}
private:
Car *pCar;
};
class CarDecorator03 : public Car
{
public:
CarDecorator03(Car *p) : pCar(p){};
void show()
{
pCar->show();
cout << ",车道偏离";
}
private:
Car *pCar;
};
int main()
{
Car *p1 = new CarDecorator01(new BMW());
p1 = new CarDecorator02(p1);
p1->show();
cout << endl;
Car *p2 = new CarDecorator02(new Audi());
p2->show();
cout << endl;
Car *p3 = new CarDecorator03(new Benc());
p3->show();
cout << endl;
return 0;
}
常见的类创建一个对象,便会得到一个新的对象。而单例模式则有些不同。
单例模式:一个类不管创建多少次对象,永远只能得到该类型一个对象的实例。可以查看C++实现MySQL数据库连接池中的线程池获取代码,将线程池定义为静态成员方法和静态成员变量,导致其处于静态变量区,只需要初始化一次。类似的日志模块应该也可以使用单例模式。
饿汉式单例模式:还没有获取实例对象,实例对象就已经产生了。
懒汉式单例模式:唯一的实例对象,直到第一次获取它的时候才产生。
下面介绍了两种单例模式的代码设计,其中提供了两种懒汉式单例模式的示例:
#include
#include
#include
using namespace std;
// 饿汉式单例模式,线程安全的
class HungrySingleton
{
public:
// 因为其不能依赖对象,所以要定义成静态成员方法,获取类的唯一实例对象的方法
static HungrySingleton* getSingleton()
{
return &instance;
}
private:
// 单例模式,不允许用户new对象,所以需要使用构造函数私有化
HungrySingleton()
{
}
static HungrySingleton instance;
// 将拷贝构造函数和赋值操作符重载进行删除,使其不能完成对象创建,只能依赖getSingleton过去唯一的实例化对象
HungrySingleton& operator=(const HungrySingleton &) = delete;
HungrySingleton(const HungrySingleton &) = delete;
};
// 类内定义,类外初始化,更多static初始化查看 https://blog.csdn.net/sevenjoin/article/details/81772792
// 静态成员在数据段,在main函数之前就创建了,如果不使用的话,这个资源就浪费了
HungrySingleton HungrySingleton::instance;
mutex lazySingletonMtx;
// 懒汉式单例模式,线程安全的
class LazySingleton
{
public:
// 因为其不能依赖对象,所以要定义成静态成员方法,获取类的唯一实例对象的方法
// 可重入函数的概念?一个线程还没执行完,该函数不能被另一个线程执行,也就是线程互斥
static LazySingleton *getSingleton()
{
if(instance==nullptr)
{
lock_guard<mutex> lck(lazySingletonMtx); // 所以多线程环境下需要加锁和双重判断
/*
不是线程安全,下面这个instance = new LazySingleton()需要执行-:开辟内存、构造对象、instance赋值
*/
if(instance==nullptr)
{
// 双重判断,防止两个线程同时进入上层的if判断中
instance = new LazySingleton();
}
}
return instance;
}
private:
// 单例模式,不允许用户new对象,所以需要使用构造函数私有化
LazySingleton()
{
}
static LazySingleton*volatile instance;
// 将拷贝构造函数和赋值操作符重载进行删除,使其不能完成对象创建,只能依赖getSingleton过去唯一的实例化对象
LazySingleton &operator=(const LazySingleton &) = delete;
LazySingleton(const LazySingleton &) = delete;
};
// 类内定义,类外初始化,更多static初始化查看 https://blog.csdn.net/sevenjoin/article/details/81772792
// 静态成员在数据段,在main函数之前就创建了,如果不使用的话,这个资源就浪费了
LazySingleton*volatile LazySingleton::instance=nullptr;
// 懒汉式单例模式,线程安全的
class LazySingleton2
{
public:
// 因为其不能依赖对象,所以要定义成静态成员方法,获取类的唯一实例对象的方法
// 可重入函数的概念?一个线程还没执行完,该函数不能被另一个线程执行,也就是线程互斥
static LazySingleton2 *getSingleton()
{
// 静态对象,运行到这个函数才开始初始化
// 函数静态局部变量的初始化,在汇编指令上已经自动添加线程互斥指令
static LazySingleton2 instance;
return &instance;
}
private:
// 单例模式,不允许用户new对象,所以需要使用构造函数私有化
LazySingleton2()
{
}
// 将拷贝构造函数和赋值操作符重载进行删除,使其不能完成对象创建,只能依赖getSingleton过去唯一的实例化对象
LazySingleton2 &operator=(const LazySingleton2 &) = delete;
LazySingleton2(const LazySingleton2 &) = delete;
};
int main()
{
HungrySingleton *p1 = HungrySingleton::getSingleton();
HungrySingleton *p2 = HungrySingleton::getSingleton();
HungrySingleton *p3 = HungrySingleton::getSingleton();
cout << p1 << " " << p2 << " " << p3 << endl; // 0x407030 0x407030 0x407030
LazySingleton *p4 = LazySingleton::getSingleton();
LazySingleton *p5 = LazySingleton::getSingleton();
LazySingleton *p6 = LazySingleton::getSingleton();
cout << p4 << " " << p5 << " " << p6 << endl; // 0x25d2430 0x25d2430 0x25d2430
// HungrySingleton t = *p1; // 拷贝构造函数私有化之后就不能完成拷贝构造了
return 0;
}
一般情况下第二种懒汉式单例模式用的比较多,也更简单,在静态成员方法中定义静态成员对象。