【C++入门精讲22】常见设计模式

一、知识点总回顾(移动语义 + 智能指针)

核心知识点

  1. 移动语义

    • 作用:转移对象资源所有权,避免低效深拷贝,提升性能
    • 触发方式:std::move() 将对象转为右值引用
    • 核心函数:移动构造函数 类名(类名&&)、移动赋值重载 返回值 operator=(类名&&)
    • 编译器默认生成函数:无参构造、拷贝构造、移动构造、拷贝赋值、移动赋值、析构函数
  2. 智能指针(RAII 资源管理)

    • 核心思想:利用类生命周期自动管理堆裸指针,构造获取资源,析构释放资源,防止内存泄漏
    • 自定义智能指针必备接口:构造函数、析构函数、operator->(指针访问)、operator*(解引用)、get()(获取原生指针)、reset()(手动释放资源)
    • C++11 标准智能指针
      • unique_ptr:独占式智能指针,同一资源仅能被一个指针管理
      • shared_ptr:共享式智能指针,内部引用计数,多指针共管同一资源
      • weak_ptr:弱引用指针,不增加引用计数 ,专门解决 shared_ptr 循环引用问题,必须依托 shared_ptr 使用

对应代码

cpp 复制代码
//综合应用
/*
*回顾知识点:
* 1.移动语义; 将某一个对象的数据转移到另一个对象中,避免不必要的拷贝,
* 1) std::move()触发
* 2)移动构造函数:类名(类名&&)
* 3)移动赋值重载; 返回类型 operator=(类名&&)
* 
* 一个类编译器默认提供无参构造,拷贝构造,移动构造,拷贝赋值,移动赋值,析构函数
* 
* 2.智能指针 : 依据类的生命周期(构造函数,析构函数)去自动管理原生指针,也叫做裸指针
* 1)自定义智能指针:
* 构造函数(数据类型 *):RAII(资源获取即初始化)
* 析构函数:  回收原始的指针
* operator -> () 指针访问
* operator*(): 指针解引用
* 数据类型 * get(): 获取原始指针,返回原始指针,但原始指针的生命周期仍然受智能指针控制。使用 get() 时需要小心,避免与智能指针的自动管理机制冲突。
* void reset():手动释放原始指针
* 
* 2)C加加11提供的智能指针: 类模板
* auto_ptr<数据类型>:放弃
* unique_ptr<数据类型>:独占
* shared_ptr<数据类型>:共享
* weak_ptr<数据类型>:弱引用
*   必须指向shared_ptr,但是不增加引用计数
* 用于解决shared_ptr 的循环引用问题
*/

二、设计模式基础介绍

核心知识点

  1. 设计模式:共 23 种经典设计模式,用于规范类与代码结构,简化设计、提升代码扩展性、可维护性。
  2. 三大分类:创建型模式、结构型模式、行为型模式。

对应代码

cpp 复制代码
//1.设计模式:  类的设计模式 (23种),分三大类型(创建类型,结构类型,行为类型)
//简化类的设计,提高程序的扩展性等

三、单例设计模式

核心知识点

  1. 单例模式 :整个程序生命周期内,类有且仅有一个实例对象
  2. 两大实现方式
    • 懒汉式:第一次使用对象时才创建实例,延迟加载。
    • 饿汉式:程序启动、类加载时就提前创建实例,无论是否使用。
  3. 单例实现步骤
    1. 私有化构造函数,禁止外部创建对象;
    2. 删除拷贝构造、移动构造、拷贝赋值,禁止克隆对象;
    3. 提供 public 静态成员函数,对外获取唯一实例;
    4. 饿汉式:定义静态类对象作为唯一实例;懒汉式:在静态函数内定义局部静态对象。

对应代码

cpp 复制代码
//2.单例设计模式: 要求类的对象,在整体程序的生命周期内,只能创建一个类的对象。
// 按创建类对象的时机或位置,分为两个单例模式:
//1)懒汉式:第一次使用对象时,才创建对象,使用的时候才会创建
//2)饿汉式:程序启动时,就创建对象,类定义即创建我们的实例对象,无论是否使用,都会提前创建好
#if 0
#include<iostream>
using namespace std;

//定义web服务器: 之创建一个类的对象
//单例设计过程: 1)私有化构造函数 2)删除拷贝构造和移动构造(整个程序只能有一个,那么你就不能被克隆或者克隆)
//3)提供一个public静态函数,返回一个类的对象
//4)懒汉式;静态成员函数种去创建成员对象
//5)饿汉式:定义静态成员 类对象,在静态成员函数种返回这个类的对象
class WebServer {
	int port;
	string root;//web资源文件的跟目录
	WebServer(int port = 443, string root = "/webroot") :port(port), root(root) {
	}
	WebServer(const WebServer&) = delete;
	WebServer& operator=(const WebServer&) = delete;
	WebServer(WebServer&&) = delete;//删除移动构造
public:

	void start() {
		cout << "Webserver Running localhost" << port << endl;
	}
	void shutdown() {
		cout << "WebServer Stop" << endl;
	}
	//静态的成员函数的参数表尽量同构造函数的参数表相同
	static WebServer& getInstance(int port, string root) {
		//懒汉式
		//static WebServer server(port, root);//局部的static 对象,在程序运行期间,只会定义一次
		//return sever;
		return intance;
	}	
	//饿汉模式
	static WebServer intance;//只是声明
};

void runServer() {
	WebServer::getInstance(8080, "/webroot").start();
}

void stopServer() {
	WebServer::getInstance(8080, "/webroot").shutdown();
}


WebServer WebServer::intance(8080);//定义


int main() {
    WebServer::getInstance(8080,"/webroot").start();

}

#endif

四、工厂设计模式

4.1 模式分类 & 核心知识点

  1. 简单工厂
    • 特点:一个工厂类生产所有产品,产品类型固定,新增产品需要修改工厂代码,违反开闭原则
    • 开闭原则:对扩展开放,对原有代码修改关闭。
  2. 工厂方法
    • 特点:一个工厂只负责生产一种产品,不同产品对应专属工厂,遵循开闭原则。
  3. 抽象工厂
    • 特点:一个工厂可以生产同系列 / 多类组合产品(如手机、平板、电脑),解决工厂方法单一产品的局限性。
  4. 通用结构:抽象产品接口 → 具体产品类 → 抽象工厂接口 → 具体工厂类。

4.2 对应代码

cpp 复制代码
#if 0
#include<iostream>
using namespace std;

//3.工厂设计模式:思考铲平如何通过工厂生产出来的
//简单工厂:工厂只需要用户一共产品类型,即可以生产出来,生产的东西只能是固定的,不能生产它没有的,违反了开闭原则。
// 开闭原则:在不该现有代码的基础上,对扩展开放,对修改关闭
//工厂方法:不同的产品可以由不同的工厂生产出来,例如:苹果手机由苹果工厂生产(只能生产手机),小米手机由小米工厂生产
//前两种都是一个工厂只能生产一种产品,
//抽象工厂; 不同的工厂可以生成相同类型或组合的产品,即一个工厂可以生产多个不同类型的产品例如:苹果工厂可以生产苹果手机,苹果电脑等
//解决工厂方法的单一性,抽象工厂可以生产组合或套装产品(或同系列)
//产品类: 抽象类或者接口
// 产品类: 抽象类或接口
class IPhone {
public:
    // 产品的功能
    virtual void tell(string num) = 0;
};

// 定义具体的产品:  某一种类型
class HWPhone : public IPhone {
public:
    void tell(string num) {
        cout << "HWPhone tell: " << num << endl;
    }
};


class VivoPhone : public IPhone {
public:
    void tell(string num) {
        cout << "VivoPhone tell: " << num << endl;
    }
};

class MIPhone : public IPhone {
public:
    void tell(string num) {
        cout << "MIPhone tell: " << num << endl;
    }
};

// 简单工厂:  产品类型固定, 定义好之后无法扩展
class PhoneFactory {
public:
    enum Type
    {
        HW,
        VIVO,
        MI
    };

    // 依据用户的提供产品类型 来生产
    static shared_ptr<IPhone> create(Type type = HW) {
        switch (type) {
        case HW: return shared_ptr<IPhone>(new HWPhone());
        case VIVO: return shared_ptr<IPhone>(new VivoPhone());
        default: return shared_ptr<IPhone>(new MIPhone());
        }
    }
};

#if 0
int main() {
    shared_ptr<IPhone> phone = PhoneFactory::create();
    phone->tell("110");


    shared_ptr<IPhone> phone2 = PhoneFactory::create(PhoneFactory::VIVO);
    phone2->tell("120");

    return 0;
}
#endif

//工厂方法设计模式: 每一个工厂只负责一个产品的生产

class IFactory {
public:
    virtual shared_ptr<IPhone> create()=0;
};

class HWFactory : public IFactory {
public:
    shared_ptr<IPhone> create() {
        return shared_ptr<IPhone>(new HWPhone());
    }
    shared_ptr<IPhone> create2() {
        return shared_ptr<IPhone>(new VivoPhone());
    }
    shared_ptr<IPhone> create3() {
        return shared_ptr<IPhone>(new MIPhone());
    }
};

#if 0
int main() {
    //需要HWPhone,只需要通过它的工厂生产即可。
    shared_ptr<IPhone> phone = HWFactory().create();
    phone->tell("110");
    return 0;
}
#endif
#if 1
//抽象工厂,工厂可以生产同类型或品牌的系列产品
class IPad {
public:
    virtual void playGame() = 0;
};

class IComputer {//电脑产品接口
public:
    virtual void softDev() = 0;

};

class HWPad :public IPad {
public:
    void playGame() {
        cout << "HWPad playGame()" << endl;
    }
};

class XMPad :public IPad {
public:
    void playGame() {
        cout << "XMPad playGame()" << endl;
    }
};

class VIvoPad :public IPad {
public:
    void playGame() {
        cout << "VIvoPad playGame()" << endl;
    }
};

class HWComputer :public IComputer {
public:
    void softDev() {
        cout << "HW" << endl;
    }
};

class XMComputer :public IComputer {
public:
    void softDev() {
        cout << "XM" << endl;
    }
};

class VIvoComputer:public IComputer {
public:
    void softDev() {
        cout << "VIvo" << endl;
    }
};
//抽象工厂的接口类
class IFactory {
public:
    virtual shared_ptr<IPhone> createPhone() = 0;
    virtual shared_ptr<IPad>  createPad() = 0;
    virtual shared_ptr<IComputer> createComputer() = 0;
};

class HWFactory : public IFactory {
public:
    shared_ptr<IPhone> createPhone() {
        return shared_ptr<IPhone>(new HWPhone());
    }
    shared_ptr<IPad> createPad() {
        return shared_ptr<IPad>(new HWPad());
    }
    shared_ptr<IComputer> createComputer() {
        return shared_ptr<IComputer>(new HWComputer());
    }
};

class XMFactory : public IFactory {
public:
    shared_ptr<IPhone> createPhone() {
        return shared_ptr<IPhone>(new MIPhone());
    }
    shared_ptr<IPad> createPad() {
        return shared_ptr<IPad>(new XMPad());
    }
    shared_ptr<IComputer> createComputer() {
        return shared_ptr<IComputer>(new XMComputer());
    }
};

class VIvoFactory : public IFactory {
public:
    shared_ptr<IPhone> createPhone() {
        return shared_ptr<IPhone>(new VivoPhone());
    }
    shared_ptr<IPad> createPad() {
        return shared_ptr<IPad>(new VIvoPad());
    }
    shared_ptr<IComputer> createComputer() {
        return shared_ptr<IComputer>(new VIvoComputer());
    }
};
#endif
#endif

五、观察者模式

核心知识点

  1. 观察者模式 :俗称发布 - 订阅模式,属于行为型设计模式。
  2. 两大核心角色
    • 主题(发布者):维护核心数据、观察者列表;提供注册 / 注销观察者、数据更新、批量通知接口。
    • 观察者(订阅者):实现统一更新接口,接收主题推送的消息并响应。
  3. 运行逻辑:主题数据发生变化 → 主动通知所有已注册观察者 → 观察者执行自身更新逻辑。

对应代码

cpp 复制代码
#if 0
#include<iostream>
#include<vector>
using namespace std;
//4.观察者模式:简化版的发布与订阅模式
//  组成: 主题,观察者
// 主题:核心数据(天气,GPS位置,网络时间)
// 要求必须有
//添加或删除观察者,更新数据函数,通知接口

//观察者: 必须存在 接收主题通知的函数 (如 update )
//被动性的,当我们关注的主题数据发生变化时,会被主题通知,然后执行自己的更新函数
//设计主题类

// 设计观察者接口类
class INTObserver {
public:
    virtual void update(string timeStr) = 0;
};


// 设计主题类
class NetworkTimerServer {
    string current_time;  // 数据
    vector<shared_ptr<INTObserver>> allOb; // 所有注册的观察者
public:
    NetworkTimerServer() :current_time("") {}

    // 注册观察者
    void regist(shared_ptr<INTObserver> ob) {
        allOb.push_back(ob);
    }

    // 取消注册观察者
    void unregist(shared_ptr<INTObserver> ob) {
        auto it = allOb.begin();
        while (it != allOb.end()) {
            if (it->get() == ob.get()) {
                allOb.erase(it);
                break;
            }
        }
    }
    void setCurrentTime(const string& timeStr) {
        this->current_time = timeStr;
        notify();
    }
    string getCurrentTime() {
        return this->current_time;
    }

    void notify() {
        // 通知所有观察者数据发生了变化
        for (auto ob : allOb) {
            ob->update(current_time);
        }
    }
};

// 设计具体的观察者
class PhoneObserver : public INTObserver {
public:
    void update(string timeStr) override {
        cout << "PhoneObserver Current Time: " << timeStr << endl;
    }
};

class PadObserver : public INTObserver {
public:
    void update(string timeStr) override {
        cout << "PadObserver Current Time: " << timeStr << endl;
    }
};

class WatchObserver : public INTObserver {
    int i;
public:
    WatchObserver() :i(0) {}
    void update(string timeStr) override {
        if (i % 4 == 0)
            cout << "WatchObserver Current Time: " << timeStr << endl;
        i++;
    }
};

#include <thread>
#include <iomanip>
#include <chrono>
#include <sstream>

int main() {
    // register int i = 0;  // 建议变量存储在寄存器中
    unique_ptr<NetworkTimerServer> nts(new NetworkTimerServer());

    shared_ptr<INTObserver> ob1 = shared_ptr<INTObserver>(new PhoneObserver());
    shared_ptr<INTObserver> ob2 = shared_ptr<INTObserver>(new PadObserver());
    shared_ptr<INTObserver> ob3 = shared_ptr<INTObserver>(new WatchObserver());
    nts->regist(ob1);
    nts->regist(ob2);
    nts->regist(ob3);

    // 模拟时钟
    for (int i = 0; i < 10; i++) {
        auto ct = chrono::system_clock::now();
        time_t tt = chrono::system_clock::to_time_t(ct);

        ostringstream oss;
        oss << put_time(localtime(&tt), "%Y-%m-%d %H:%M:%S");

        // 更新时间
        nts->setCurrentTime(oss.str());

        // 休息1s
        this_thread::sleep_for(chrono::seconds(1));
    }

    return 0;
}
#endif

六、构建器模式(建造者模式)

核心知识点

  1. 构建器模式 :用于成员属性繁多、构造函数重载复杂的类,拆分对象创建步骤,实现流式构建。
  2. 实现步骤
    1. 私有化外部类构造函数,禁止外部直接实例化;
    2. 定义静态内部构建器类 Builder
    3. Builder 中提供链式成员函数,逐个设置对象属性;
    4. 最终通过 build() 方法生成并返回完整对象。
  3. 流式构建:成员函数返回构建器自身引用,支持连续调用。

对应原版代码

cpp 复制代码
#if 0
#include <iostream>
using namespace std;

// 1. 构建器模式
//    将复杂性创建对象的类,设计为分层次的创建过程。
//    复杂性创建,如:  类的成员属性较多, 构造函数重载也非常多
//   构建器模式的设计过程:    【流式构建器】 
//     1)  私有化构造函数, 隐藏类对象的创建过程
//     2)  在类内设计静态公开的成员类 (内部类) 为   构建器类 Builder
//     3) 在Builder 类内,设计公开的成员函数,提供属性的设计 为 构建过程(层次)
//         最后提供一个 build()函数返回 外部类的对象。

#include <memory>

class Computer {
    string vendor; // 厂家
    string cpuName; // 处理器名称
    int cpuNum; // 内核数
    int memorySize; // 内存大小
    int ssdSize; // 硬盘大小
    // ... 其他大量的属性
private:
    Computer() :vendor("中国"), cpuName("Intel"), cpuNum(2), memorySize(4), ssdSize(40) {}
    Computer(string vendor) :vendor(vendor), cpuName("Intel"), cpuNum(2), memorySize(4), ssdSize(40) {}
    Computer(string vendor, string cpuName) :vendor(vendor), cpuName(cpuName), cpuNum(2), memorySize(4), ssdSize(40) {}
    Computer(string vendor, string cpuName, int cpuNum)
        :vendor(vendor), cpuName(cpuName),
        cpuNum(cpuNum), memorySize(4), ssdSize(40) {
    }

    Computer(string vendor, string cpuName, int cpuNum, int memorySize)
        :vendor(vendor), cpuName(cpuName),
        cpuNum(cpuNum), memorySize(memorySize), ssdSize(40) {
    }

    Computer(string vendor, string cpuName, int cpuNum, int memorySize, int ssdSize)
        :vendor(vendor), cpuName(cpuName),
        cpuNum(cpuNum), memorySize(memorySize), ssdSize(ssdSize) {
    }
public:
    void show() {
        cout << vendor << " 生产 " << cpuName << "(" << cpuNum << ") 内存 " << memorySize << "G";
        cout << " ssd " << ssdSize << " G" << endl;
    }

    // 静态内部类:  可以访问外部类的私有成员
    static class Builder {
        shared_ptr<Computer> computer;
    public:
        Builder() {
            computer = shared_ptr<Computer>(new Computer());
        }
        // 设计构建过程成员函数:  如果返回构建器类的引用 ,称之为 流式构建
        Builder& vendor(string v) {
            computer->vendor = v;
            return *this;
        }

        Builder& cpuNum(int n) {
            computer->cpuNum = n;
            return *this;
        }

        Builder& memSize(int n) {
            computer->memorySize = n;
            return *this;
        }

        Builder& ssdSize(int n) {
            computer->ssdSize = n;
            return *this;
        }

        shared_ptr<Computer> build() {
            return computer;
        }
    };
};

int main() {
    shared_ptr<Computer> c = Computer::Builder()
        .cpuNum(8).memSize(32).ssdSize(1024).build();

    c->show();

    return 0;
}
#endif

七、附加练习代码(图形类 + STL 算法练习)

7.1 图形面积计算(多态 + 智能指针)

知识点

  • 抽象基类定义纯虚函数,实现多态;
  • 使用 unique_ptr 管理堆对象,自动释放资源。

代码

cpp 复制代码
#if 0
#include<iostream>
#include<memory>
using namespace std;
#define pai 3.14
class Shape {
public:
    virtual void alcArea() = 0;
};
class Circle :public Shape {
private:
    double  t;
    double area;
public:
    Circle(double r,double area = 0) :t(r),area(area){};
    void alcArea() override {
        area = pai * t * t;
        cout<<"圆的面积是"<<area<<endl;
    }
};

int main() {
    unique_ptr<Shape> s(new Circle(5.0));
    s.get()->alcArea();
}
#endif

7.2 vector + for_each + Lambda 练习

知识点

  • emplace_back 原位构造元素,效率高于 push_back
  • for_each 遍历算法结合 Lambda 表达式处理容器元素。

代码

cpp 复制代码
#if 0
#include<iostream>
#include<vector>
#include <algorithm>
using namespace std;
int main() {
    vector<int> v;
    v.emplace_back(1);
    v.emplace_back(3);
    v.emplace_back(5);
    v.emplace_back(7);
    v.emplace_back(9);
    for (auto v : v) {
        cout << v << endl;
   }
    for_each(v.begin(), v.end(), [](int v) {cout<<v*2<<endl; });
    return 0;
}
#endif

全文总结

  1. 前置复习:移动语义优化拷贝效率,各类智能指针基于 RAII 实现内存自动管理。
  2. 单例模式:保证全局唯一实例,分懒汉、饿汉两种实现。
  3. 工厂模式:简单工厂(违反开闭)、工厂方法(一厂一物)、抽象工厂(一厂多系列产品)。
  4. 观察者模式:发布订阅模型,主题推送消息,观察者被动响应。
  5. 构建器模式:解决多参数复杂对象创建,支持流式调用。
  6. 附加练习巩固:C++ 多态、智能指针、STL 容器与算法综合使用。
相关推荐
c++之路3 小时前
Bazel C++ 构建系列文档(三):构建第一个 C++ 项目
开发语言·c++
旖-旎3 小时前
《LeetCode 695 岛屿的最大面积 FloodFill DFS 解法》
c++·算法·力扣·深度优先遍历·floodfill
森G3 小时前
61、信号与槽机制在 TCP 编程中的应用---------网络编程
网络·c++·qt·网络协议·tcp/ip
syagain_zsx4 小时前
STL 之 vector 讲练结合
c++·算法
牛油果子哥q4 小时前
STL set与map底层精讲,红黑树适配原理、有序去重特性、迭代器遍历、API实战与面试核心考点全解
开发语言·数据结构·c++·面试
奇妙方程式5 小时前
2026年第九届GXCPC广西大学生程序设计大赛(热身赛)题解
c++·编程比赛·编程竞赛·gxcpc
Tian_Hang5 小时前
C++原型模式(Protype)
开发语言·c++·算法
FL16238631296 小时前
[cmake]基于C++使用纯opencv部署ppocrv5v6的onnx模型
开发语言·c++·opencv
玖玥拾6 小时前
C/C++ 数据结构(六)链表迭代器与底层
c语言·数据结构·c++·链表·stl库