单例模式
定义:旨在确保类只有一个实例,并提供一个全局访问点来访问该实例。单例模式通常用于需要在整个应用程序中共享相同对象实例的情况,例如全局配置对象、日志对象、数据库连接等。
人话:只在程序程序运行的时候初始化一次,初始化完成之后无论是再执行构造、拷贝构造、移动拷贝构造都不会新创建一个对象。c++最简单的就是使用static修饰类初始化函数和成员变量,因为static在c++中是线程安全的,但是注意在其它语言中不一定。
demo:
public class Singleton {private static Singleton instance;private Singleton() {// 私有化构造函数,防止外部实例化}public static Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}
}
工厂模式
定义:封装对象的创建过程,使得客户端代码不需要直接实例化对象,而是通过工厂类来创建对象。
demo:
#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 ExportCSVFactory();factory->Export("hello world");return 0;
}
抽象工厂
定义:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
人话:工厂模式的升级版本,写程序的时候可能有若干个工厂,实现一个工厂创造器/生成器类,获取具体工厂,再通过具体工厂获取实例化的类对象。有条件把所有工厂的结构进行抽象,抽象出一个基类,所有工厂继承自这个基类。
# 抽象产品A
class AbstractProductA:def operation(self):pass# 具体产品A1
class ConcreteProductA1(AbstractProductA):def operation(self):return "Product A1 operation"# 具体产品A2
class ConcreteProductA2(AbstractProductA):def operation(self):return "Product A2 operation"# 抽象产品B
class AbstractProductB:def operation(self):pass# 具体产品B1
class ConcreteProductB1(AbstractProductB):def operation(self):return "Product B1 operation"# 具体产品B2
class ConcreteProductB2(AbstractProductB):def operation(self):return "Product B2 operation"# 抽象工厂
class AbstractFactory:def create_product_a(self):passdef create_product_b(self):pass# 具体工厂1
class ConcreteFactory1(AbstractFactory):def create_product_a(self):return ConcreteProductA1()def create_product_b(self):return ConcreteProductB1()# 具体工厂2
class ConcreteFactory2(AbstractFactory):def create_product_a(self):return ConcreteProductA2()def create_product_b(self):return ConcreteProductB2()# 客户端代码
factory_type = 1
if factory_type == 1:factory = ConcreteFactory1()
elif factory_type == 2:factory = ConcreteFactory2()product_a = factory.create_product_a()
product_b = factory.create_product_b()print(product_a.operation()) # Output: Product A1 operation
print(product_b.operation()) # Output: Product B1 operation
责任链
定义:许多个对象都有机会处理请求,从而避免请求的发送者与接收者之间的直接耦合。在责任链模式中,请求沿着一个链传递,直到有一个对象处理它为止。
人话:把处理对象封装在一个函数或者类的内部,然后按照执行这些处理对象,每个处理对象可能解决部分问题,直到问题被全部解决。
demo:
#include <memory>
#include <string>class Context {
public:std::string name;int day;
};// 稳定点 抽象 变化点 扩展 (多态)
// 从单个处理节点出发,我能处理,我处理,我不能处理交给下一个人处理
// 链表关系如何抽象class HandleByMainProgram;
class HandleByProjMgr;
class HandleByBoss;
class HandleByBeauty;class IHandler {
public:IHandler() : next(nullptr) {}virtual ~IHandler();void SetNextHandler(IHandler *next) { // 链表关系next = next;}bool Handle(const Context &ctx) {if (CanHandle(ctx)) {return HandleRequest(ctx);} else if (GetNextHandler()) {return GetNextHandler()->Handle(ctx);} else {// err}return false;}
protected:virtual bool HandleRequest(const Context &ctx) = 0;virtual bool CanHandle(const Context &ctx) = 0;IHandler * GetNextHandler() {return next;}
private:IHandler *next; // 组合基类指针
};class Request {
public:Request() {IHandler * h0 = new HandleByBeauty();IHandler * h1 = new HandleByMainProgram();IHandler * h2 = new HandleByProjMgr();IHandler * h3 = new HandleByBoss();h0->SetNextHandler(h1);h1->SetNextHandler(h2);h2->SetNextHandler(h3);handler = h0;}bool Handle(const Context &ctx) {return handler->Handle(ctx);}
private:IHandler *handler;
};class HandleByMainProgram : public IHandler {
protected:virtual bool HandleRequest(const Context &ctx){//return true;}virtual bool CanHandle(const Context &ctx) {//if (ctx.day <= 1)return true;return false;}
};class HandleByProjMgr : public IHandler {
protected:virtual bool HandleRequest(const Context &ctx){//return true;}virtual bool CanHandle(const Context &ctx) {//if (ctx.day <= 20)return true;return false;}
};
class HandleByBoss : public IHandler {
protected:virtual bool HandleRequest(const Context &ctx){//return true;}virtual bool CanHandle(const Context &ctx) {//if (ctx.day < 30)return true;return false;}
};class HandleByBeauty : public IHandler {
protected:virtual bool HandleRequest(const Context &ctx){//return true;}virtual bool CanHandle(const Context &ctx) {//if (ctx.day <= 3)return true;return false;}
};int main() {
// 抽象工厂
// nginx http 处理 // 设置下一指针 Context ctx;auto req = std::make_unique<Request>();req->Handle(ctx);return 0;
}
装饰器
定义:过组合和递归组合的方式来动态地增加对象的功能,而不是通过修改现有类的接口来实现功能的扩展。
人话:在不改变原有接口的基础上通过组合、继承等手段重写或扩展原始对象的方法。
demo:
#include <iostream>
// 普通员工有销售奖金,累计奖金,部门经理除此之外还有团队奖金;后面可能会添加环比增长奖金,同时可能产生不同的奖金组合;
// 销售奖金 = 当月销售额 * 4%
// 累计奖金 = 总的回款额 * 0.2%
// 部门奖金 = 团队销售额 * 1%
// 环比奖金 = (当月销售额-上月销售额) * 1%
// 销售后面的参数可能会调整
using namespace std;
class Context {
public:bool isMgr;// User user;// double groupsale;
};class CalcBonus {
public:CalcBonus(CalcBonus * c = nullptr) : cc(c) {}virtual double Calc(Context &ctx) {return 0.0; // 基本工资}virtual ~CalcBonus() {}protected:CalcBonus* cc;
};class CalcMonthBonus : public CalcBonus {
public:CalcMonthBonus(CalcBonus * c) : CalcBonus(c) {}virtual double Calc(Context &ctx) {double mbonus /*= 计算流程忽略*/; return mbonus + cc->Calc(ctx);}
};class CalcSumBonus : public CalcBonus {
public:CalcSumBonus(CalcBonus * c) : CalcBonus(c) {}virtual double Calc(Context &ctx) {double sbonus /*= 计算流程忽略*/; return sbonus + cc->Calc(ctx);}
};class CalcGroupBonus : public CalcBonus {
public:CalcGroupBonus(CalcBonus * c) : CalcBonus(c) {}virtual double Calc(Context &ctx) {double gbnonus /*= 计算流程忽略*/; return gbnonus + cc->Calc(ctx);}
};class CalcCycleBonus : public CalcBonus {
public:CalcCycleBonus(CalcBonus * c) : CalcBonus(c) {}virtual double Calc(Context &ctx) {double gbnonus /*= 计算流程忽略*/; return gbnonus + cc->Calc(ctx);}
};int main() {// 1. 普通员工Context ctx1;CalcBonus *base = new CalcBonus();CalcBonus *cb1 = new CalcMonthBonus(base);CalcBonus *cb2 = new CalcSumBonus(cb1);cb2->Calc(ctx1);// 2. 部门经理Context ctx2;CalcBonus *cb3 = new CalcGroupBonus(cb1);cb3->Calc(ctx2);
}
组合模式
定义:又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。
人话:类的嵌套,把相似的类存储到一个容器中,一般容器对象和叶子对象通常实现同一个接口或继承同一个抽象类
demo:
class IComponent
{
public:IComponent(/* args */);~IComponent();virtual void Execute() = 0;virtual void AddChild(IComponent *ele) {}virtual void RemoveChild(IComponent *ele) {}
};class Leaf : public IComponent{
public:virtual void Execute() {cout << "leaf exxcute" << endl;}
};class Composite : public IComponent
{
private:std::list<IComponent*> _list;
public:virtual void AddChild(IComponent *ele) {// ...}virtual void RemoveChild(IComponent *ele) {// ...}virtual void Execute() {for (auto iter = _list.begin(); iter != _list.end(); iter++) {iter->Execute();}}
};
适配器
定义:主要目的是将一个接口转换成客户希望的另一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以协同工作
demo:
#include <iostream>
#include <string>// MP3播放器接口
class MP3Player {
public:virtual ~MP3Player() {}virtual void play(const std::string& audioFilePath) = 0;
};// WAV播放器类
class WAVPlayer {
public:void playWAV(const std::string& wavFilePath) {std::cout << "Playing WAV file: " << wavFilePath << std::endl;}
};// WAV转MP3适配器
class WAVtoMP3Adapter : public MP3Player {
private:WAVPlayer wavPlayer;public:void play(const std::string& audioFilePath) override {// 假设音频文件名后缀转换逻辑,实际上应根据实际情况调整std::string convertedFilePath = audioFilePath.substr(0, audioFilePath.find_last_of('.')) + ".wav";wavPlayer.playWAV(convertedFilePath);}
};int main() {// 创建适配器实例,模拟播放MP3文件WAVtoMP3Adapter adapter;// 尝试播放一个"MP3"文件,实际上通过适配器播放WAVadapter.play("favorite_song.mp3");return 0;
}
这是一条吃饭博客,由挨踢零声赞助。学C/C++就找挨踢零声,加入挨踢零声,面试不挨踢!