持续更新!!!
开放封闭原则:
封闭:已经开发好的类不能再修改。
依赖倒转原则:
设计模式三原则 | 爱编程的大丙 核心:多态!!!!!
通过父类设置虚函数,子类继承父类,重写虚函数,这样高层和底层通过抽象类解耦了。
(这里所说的抽象类不一定有纯虚函数) 扩展性
里氏代换原则:
父类定义的属性对于子类来说是完全适用的,不完全适用该原则无法满足。-----导致 依赖倒转原则不满足(原则是层层递进的关系)
单例模式:
类的对象只能创建出一个!! new
任务队列:
有一定的容量,可以存储任务
按照下单的先后顺序存储并处理任务 – 典型的队列特性:先进先出
在一个项目中,全局范围内,某个类的实例有且仅有一个,通过这个唯一实例向其他模块提供数据的全局访问,这种模式就叫单例模式。单例模式的典型应用就是任务队列。
使用单例模式,将全局变量封装到一个类里面!!!!!防止被恶意篡改!
🔹 单例模式的核心要点:
保证类只有一个实例。
提供一个全局访问点。
防止拷贝和移动构造,通常通过 delete 禁止拷贝、移动操作。
支持线程安全,可以使用 std::call_once 或 C++11 局部静态变量(推荐)。
根据需求选择懒汉式(Lazy Singleton)或饿汉式(Eager Singleton)。
C++11知识点:
default表示使用函数的默认行为。
饿汉模式:
定义了类 new了一个内存 但是没有使用!---适用于多线程直接访问,没有线程安全问题的(多线程可以同时访问单例的对象)
#include<iostream>
//1.不带参数的构造函数 2.拷贝构造函数 3.移动构造函数(资源对象的转移--但是对象有且还是只有一个)
// 定义一个单例模式的类
不能让用户在类的外边 去调用它的构造函数
1.不带参数的构造函数 2.拷贝构造函数
以上两种要被禁用:1.放到类的私有中 外部不能访问 2.用C++11的新特性 delete禁用
class TaskQueue
{
public:
// = delete 代表函数禁用, 也可以将其访问权限设置为私有
TaskQueue(const TaskQueue& obj) = delete;
TaskQueue& operator=(const TaskQueue& obj) = delete;
static TaskQueue* getInstance()
{
return m_taskQ;
}
private:
TaskQueue() = default;
static TaskQueue* m_taskQ;
};
// 静态成员初始化放到类外部处理 语法要求
TaskQueue* TaskQueue::m_taskQ = new TaskQueue;
int main()
{
TaskQueue* obj = TaskQueue::getInstance();
}
/*
只能通过类名来得到实例化对象,这个对象肯定是一个静态的对象!!!为什么呢?
只有静态的成员函数和成员变量才属于类
类里面的静态成员变量需要在类外面进行初始化*/
为什么单例对象通常是静态的?
1. 静态对象的生命周期与程序相同
静态对象的生命周期从程序启动时开始,到程序结束时结束。这与单例模式的要求非常契合,因为单例对象需要在整个程序运行期间一直存在。
2. 静态对象属于类,而不是某个具体对象
静态成员变量属于类本身,而不是某个具体的对象。这意味着它可以通过类名直接访问,而不需要创建对象。这符合单例模式提供全局访问点的要求。
3. 避免重复实例化
如果单例对象不是静态的,那么每次通过类名调用获取实例的方法时,都可能需要重新创建对象,这违背了单例模式“确保只有一个实例”的原则。而静态对象在第一次创建后会一直存在,后续访问时可以直接返回同一个对象。
在单例模式中,实例对象通常是静态的,原因如下:
-
静态对象的生命周期与程序相同,符合单例模式的要求。
-
静态对象属于类,可以通过类名直接访问,提供全局访问点。
-
静态对象避免了重复实例化,确保了单例的唯一性。
懒汉模式
线程安全问题
多个线程可能会同时new 多个对象,访问这个实例
假设多个线程几乎同时调用 getInstance()
方法,而此时 instance
还未被初始化。每个线程都可能检查到 instance
为 nullptr
,然后各自创建一个新的实例。这会导致多个实例被创建,违反了单例模式的“唯一性”原则-------------互斥锁
// 懒汉模式
class TaskQueue
{
public:
// = delete 代表函数禁用, 也可以将其访问权限设置为私有
TaskQueue(const TaskQueue& obj) = delete;
TaskQueue& operator=(const TaskQueue& obj) = delete;
static TaskQueue* getInstance()
{
if(m_taskQ == nullptr)
{
m_taskQ = new TaskQueue;
}
return m_taskQ;
}
private:
TaskQueue() = default;
static TaskQueue* m_taskQ;
};
TaskQueue* TaskQueue::m_taskQ = nullptr;
线程同步:让线程按顺序依次进行!!!!
双重检查锁定:
提高了效率,只有第一次同步访问,第二次以后并行访问!!
class TaskQueue
{
public:
// = delete 代表函数禁用, 也可以将其访问权限设置为私有
TaskQueue(const TaskQueue& obj) = delete;
TaskQueue& operator=(const TaskQueue& obj) = delete;
static TaskQueue* getInstance()
{
if (m_taskQ == nullptr)//第一重检查
{
m_mutex.lock();
if (m_taskQ == nullptr) //第二重检查
{
m_taskQ = new TaskQueue;
}
m_mutex.unlock();
}
return m_taskQ;
}
private:
TaskQueue() = default;
static TaskQueue* m_taskQ;
static mutex m_mutex;
};
TaskQueue* TaskQueue::m_taskQ = nullptr;
mutex TaskQueue::m_mutex; //外部需要声明!!!!!注意!!!!!!!!!!
双重锁定的问题:
但是实际上 m_taskQ = new TaskQueue; 在执行过程中对应的机器指令可能会被重新排序。正常过程如下:
第一步:分配内存用于保存 TaskQueue 对象。
第二步:在分配的内存中构造一个 TaskQueue 对象(初始化内存)。
第三步:使用 m_taskQ 指针指向分配的内存。
但是被重新排序以后执行顺序可能会变成这样:
第一步:分配内存用于保存 TaskQueue 对象。
第二步:使用 m_taskQ 指针指向分配的内存。
第三步:在分配的内存中构造一个 TaskQueue 对象(初始化内存)。
原子变量:
不允许new出来的一个地址 还没有被初始化就被拿走,必须初始化,然后指针指向这个内存!!!!
控制机器指令执行的顺序!! 通过load加载数据 store存入数据
class TaskQueue
{
public:
// = delete 代表函数禁用, 也可以将其访问权限设置为私有
TaskQueue(const TaskQueue& obj) = delete;
TaskQueue& operator=(const TaskQueue& obj) = delete;
static TaskQueue* getInstance()
{
TaskQueue* queue = m_taskQ.load();
if (queue == nullptr)
{
// m_mutex.lock(); // 加锁: 方式1
lock_guard<mutex> locker(m_mutex); // 加锁: 方式2
queue = m_taskQ.load(); //重新加载:其他线程创建了指针,轮到当前线程,更新最新状态!!!!
if (queue == nullptr)
{
queue = new TaskQueue;
m_taskQ.store(queue);
}
// m_mutex.unlock();
}
return queue;
}
void print()
{
cout << "hello, world!!!" << endl;
}
private:
TaskQueue() = default;
static atomic<TaskQueue*> m_taskQ;
static mutex m_mutex;
};
atomic<TaskQueue*> TaskQueue::m_taskQ;
mutex TaskQueue::m_mutex;
int main()
{
TaskQueue* queue = TaskQueue::getInstance();
queue->print();
return 0;
}
不是静态的对象,出了一个函数{}就会被析构
单例模式---懒汉模式---多线程
使用局部对象!!! 解决线程安全问题 C++11特性已解决!!!
原因:如果指令逻辑进入一个未被初始化的声明变量,所有并发执行应当等待该变量完成初始化。
class TaskQueue
{
public:
// = delete 代表函数禁用, 也可以将其访问权限设置为私有
TaskQueue(const TaskQueue& obj) = delete;
TaskQueue& operator=(const TaskQueue& obj) = delete;
static TaskQueue* getInstance()
{
static TaskQueue taskQ;/!!!!!!!!!!!!!!!!!!!!!
return &taskQ;
}
void print()
{
cout << "hello, world!!!" << endl;
}
private:
TaskQueue() = default;
};
int main()
{
TaskQueue* queue = TaskQueue::getInstance();
queue->print();
return 0;
}
任务队列:
饿汉模式 :线程安全指的是多个线程访问单例对象没有线程安全问题,内部单例对象的数据的时候有线程安全问题。--------------------------保护!!!!!互斥锁
lock_guard<mutex> locker(m_mutex);更好的避免出现死锁问题,locker析构时候就解锁。
#include <iostream>
#include <queue>
#include <mutex>
#include <thread>
using namespace std;
class TaskQueue
{
public:
// = delete 代表函数禁用, 也可以将其访问权限设置为私有
TaskQueue(const TaskQueue& obj) = delete;
TaskQueue& operator=(const TaskQueue& obj) = delete;
static TaskQueue* getInstance()
{
return &m_obj;
}
// 任务队列是否为空
bool isEmpty()
{
lock_guard<mutex> locker(m_mutex);
bool flag = m_taskQ.empty();
return flag;
}
// 添加任务
void addTask(int data)
{
lock_guard<mutex> locker(m_mutex);
m_taskQ.push(data);
}
// 取出一个任务
int takeTask()
{
lock_guard<mutex> locker(m_mutex);
if (!m_taskQ.empty())
{
return m_taskQ.front();
}
return -1;
}
// 删除一个任务
bool popTask()
{
lock_guard<mutex> locker(m_mutex);
if (!m_taskQ.empty())
{
m_taskQ.pop();
return true;
}
return false;
}
private:
TaskQueue() = default;
static TaskQueue m_obj;
queue<int> m_taskQ; //不需要静态变量,因为是类的成员变量 属于唯一的实例
mutex m_mutex;
};
TaskQueue TaskQueue::m_obj;
int main()
{
thread t1([]() {
TaskQueue* taskQ = TaskQueue::getInstance();
for (int i = 0; i < 100; ++i)
{
taskQ->addTask(i + 100);
cout << "+++push task: " << i + 100 << ", threadID: "
<< this_thread::get_id() << endl;
this_thread::sleep_for(chrono::milliseconds(500));
}
});
thread t2([]() {
TaskQueue* taskQ = TaskQueue::getInstance();
this_thread::sleep_for(chrono::milliseconds(100));
while (!taskQ->isEmpty())
{
int data = taskQ->takeTask();
cout << "---take task: " << data << ", threadID: "
<< this_thread::get_id() << endl;
taskQ->popTask();
this_thread::sleep_for(chrono::seconds(1));//sleep_for表示休眠的长度
}
});
t1.join(); //主线程阻塞 等待子线程完成
t2.join();
}
C++11特性 C++新特性(服务器项目)-优快云博客
简单的工厂模式:
工厂类有且只有一个!!!!
工厂生产出的是产品类的子类对象!!
为什么给父类提供虚 析构函数:将子类的内存全部释放掉(不然的话直接析构了父类对象,子类没有被析构)---(继承,多态) 多个子类的情况下需要
C++中枚举会进行错误的检查,宏就不会!!
强制枚举类型! enum class(struct)---可以指定枚举的类型
enum class Type:char{SHEEP, LION, BAT};
子类可以被视为父类的“一种”,因此子类对象可以被赋值给父类类型的变量(向上转型)。
父类对象不能直接被赋值给子类类型的变量(向下转型),需要显式转换。
子类的类型不完全等同于父类的类型,因为子类可能有额外的属性和方法。
多态允许子类对象通过父类类型的引用或指针调用方法时,运行时会根据实际对象的类型执行相应的方法。
#include <iostream>
using namespace std;
class AbstractSmile
{
public:
virtual void transform() {}
virtual void ability() {}
virtual ~AbstractSmile() {}
};
// 人造恶魔果实· 绵羊形态
class SheepSmile : public AbstractSmile
{
public:
void transform() override
{
cout << "变成人兽 -- 山羊人形态..." << endl;
}
void ability() override
{
cout << "将手臂变成绵羊角的招式 -- 巨羊角" << endl;
}
};
// 人造恶魔果实· 狮子形态
class LionSmile : public AbstractSmile
{
public:
void transform() override
{
cout << "变成人兽 -- 狮子人形态..." << endl;
}
void ability() override
{
cout << "火遁· 豪火球之术..." << endl;
}
};
class BatSmile : public AbstractSmile
{
public:
void transform() override
{
cout << "变成人兽 -- 蝙蝠人形态..." << endl;
}
void ability() override
{
cout << "声纳引箭之万剑归宗..." << endl;
}
};
// 恶魔果实工厂类
enum class Type:char{SHEEP, LION, BAT};
class SmileFactory
{
public:
SmileFactory() {}
~SmileFactory() {}
AbstractSmile* createSmile(Type type)
{
AbstractSmile* ptr = nullptr;
switch (type)
{
case Type::SHEEP:
ptr = new SheepSmile;
break;
case Type::LION:
ptr = new LionSmile;
break;
case Type::BAT:
ptr = new BatSmile;
break;
default:
break;
}
return ptr;
}
};
int main()
{
SmileFactory* factory = new SmileFactory;
AbstractSmile* obj = factory->createSmile(Type::BAT);
obj->transform();
obj->ability();
return 0;
}
工厂模式:
简单来说就是:多个子类重写父类的工厂模式;
每个子工厂类负责生产一种恶魔果实,这相当于再次解耦,将工厂类的职责再次拆分、细化,如果要生产新品种的恶魔果实,那么只需要添加对应的工厂类,无需修改原有的代码。
子工厂类生产的对象是单一的,为什么还要返回接收的是父类类型?
实现程序的统一!通过父类的指针调用子类的工厂函数!!!
#include <iostream>
using namespace std;
class AbstractSmile
{
public:
virtual void transform() = 0;
virtual void ability() = 0;
virtual ~AbstractSmile() {}
};
// 人造恶魔果实· 绵羊形态
class SheepSmile : public AbstractSmile
{
public:
void transform() override
{
cout << "变成人兽 -- 山羊人形态..." << endl;
}
void ability() override
{
cout << "将手臂变成绵羊角的招式 -- 巨羊角" << endl;
}
};
// 人造恶魔果实· 狮子形态
class LionSmile : public AbstractSmile
{
public:
void transform() override
{
cout << "变成人兽 -- 狮子人形态..." << endl;
}
void ability() override
{
cout << "火遁· 豪火球之术..." << endl;
}
};
class BatSmile : public AbstractSmile
{
public:
void transform() override
{
cout << "变成人兽 -- 蝙蝠人形态..." << endl;
}
void ability() override
{
cout << "声纳引箭之万剑归宗..." << endl;
}
};
// 恶魔果实工厂类
class AbstractFactory
{
public:
virtual AbstractSmile* createSmile() = 0;
virtual ~AbstractFactory() {}
};
class SheepFactory : public AbstractFactory
{
public:
AbstractSmile* createSmile() override
{
return new SheepSmile;
}
~SheepFactory()
{
cout << "释放 SheepFactory 类相关的内存资源" << endl;
}
};
class LionFactory : public AbstractFactory
{
public:
// 工厂函数
AbstractSmile* createSmile() override
{
return new LionSmile;
}
~LionFactory()
{
cout << "释放 LionFactory 类相关的内存资源" << endl;
}
};
class BatFactory : public AbstractFactory
{
public:
// 工厂函数
AbstractSmile* createSmile() override
{
return new BatSmile;
}
~BatFactory()
{
cout << "释放 BatFactory 类相关的内存资源" << endl;
}
};
int main()
{
AbstractFactory* factory = new BatFactory;
AbstractSmile* obj = factory->createSmile();
obj->transform();
obj->ability();
return 0;
}
delete factory delete的是一个父类指针但是实现了一个多态, 通过父类指针找到了子类对象,调用了子类对象里面的析构函数,析构子类对象里面的资源!!!
基类!!!!实现多态,多态是设计模式的灵魂!!!!
抽象工厂模式:
可变因素,组合关系!
简单工厂就一个工厂类(里面枚举),这里是一个虚工厂基类,和多个工厂子类。耦合性更低!
1. 组合(Composition)
组合是一种强关联关系,表示一个类(称为“容器类”)完全拥有另一个类(称为“成员类”)的实例。组合关系通常意味着成员类的生命周期完全依赖于容器类的生命周期,即成员类的实例是容器类的一部分,当容器类被销毁时,成员类的实例也会被销毁。
特点:
-
强依赖性:成员类的实例不能独立于容器类存在。
-
生命周期绑定:容器类的生命周期决定了成员类的生命周期。
-
语义表达:通常用“部分-整体”关系来描述,例如“汽车”和“发动机”之间的关系,发动机是汽车的一部分,没有汽车,发动机就失去了意义。
2. 聚合(Aggregation)
聚合也是一种关联关系,但比组合关系弱。它表示一个类(容器类)包含另一个类(成员类)的实例,但成员类的生命周期并不依赖于容器类。换句话说,成员类的实例可以独立于容器类存在。
特点:
-
弱依赖性:成员类的实例可以独立于容器类存在。
-
生命周期独立:成员类的生命周期与容器类无关。
-
语义表达:通常用“整体-部分”关系来描述,但部分可以独立存在,例如“图书馆”和“书籍”之间的关系,书籍可以独立于图书馆存在。
简单工厂就一个工厂类(里面枚举),这里是一个虚工厂基类,和多个工厂子类。耦合性更低!
#include <iostream>
#include <string>
using namespace std;
// 船体
class ShipBody
{
public:
virtual string getShipBody() = 0;
virtual ~ShipBody() {}
};
class WoodBody : public ShipBody
{
public:
string getShipBody() override
{
return string("用<木材>制作轮船船体...");
}
};
class IronBody : public ShipBody
{
public:
string getShipBody() override
{
return string("用<钢铁>制作轮船船体...");
}
};
class MetalBody : public ShipBody
{
public:
string getShipBody() override
{
return string("用<合金>制作轮船船体...");
}
};
// 武器
class Weapon
{
public:
virtual string getWeapon() = 0;
virtual ~Weapon() {}
};
class Gun : public Weapon
{
public:
string getWeapon() override
{
return string("配备的武器是<枪>...");
}
};
class Cannon : public Weapon
{
public:
string getWeapon() override
{
return string("配备的武器是<自动机关炮>...");
}
};
class Laser : public Weapon
{
public:
string getWeapon() override
{
return string("配备的武器是<激光>...");
}
};
// 动力
class Engine
{
public:
virtual string getEngine() = 0;
virtual ~Engine() {}
};
class Human : public Engine
{
public:
string getEngine() override
{
return string("使用<人力驱动>...");
}
};
class Diesel : public Engine
{
public:
string getEngine() override
{
return string("使用<内燃机驱动>...");
}
};
class Nuclear : public Engine
{
public:
string getEngine() override
{
return string("使用<核能驱动>...");
}
};
// 轮船类
class Ship
{
public:
Ship(ShipBody* body, Weapon* weapon, Engine* engine) :
m_body(body), m_weapon(weapon), m_engine(engine)
{
}
string getProperty()
{
string info = m_body->getShipBody() + m_weapon->getWeapon() + m_engine->getEngine();
return info;
}
~Ship()
{
delete m_body;
delete m_engine;
delete m_weapon;
}
private:
ShipBody* m_body = nullptr;
Weapon* m_weapon = nullptr;
Engine* m_engine = nullptr;
};
// 工厂类
class AbstractFactory
{
public:
virtual Ship* createShip() = 0;
virtual ~AbstractFactory() {}
};
class BasicFactory : public AbstractFactory
{
public:
Ship* createShip() override
{
Ship* ship = new Ship(new WoodBody, new Gun, new Human);
cout << "<基础型>战船生产完毕, 可以下水啦..." << endl;
return ship;
}
};
class StandardFactory : public AbstractFactory
{
public:
Ship* createShip() override
{
Ship* ship = new Ship(new IronBody, new Cannon, new Diesel);
cout << "<标准型>战船生产完毕, 可以下水啦..." << endl;
return ship;
}
};
class UltimateFactory : public AbstractFactory
{
public:
Ship* createShip() override
{
Ship* ship = new Ship(new MetalBody, new Laser, new Nuclear);
cout << "<旗舰型>战船生产完毕, 可以下水啦..." << endl;
return ship;
}
};
int main()
{
AbstractFactory* factroy = new StandardFactory;
Ship* ship = factroy->createShip();
cout << ship->getProperty();
delete ship;
delete factroy;
return 0;
}
观察者模式
定义对象之间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。
稳定点:一对多的依赖关系
变化点:多增加 多的减少
你的理解基本是正确的,但可以再细化一下 观察者模式(Observer Pattern) 的核心概念和实现方式。
观察者模式的核心要素
观察者模式主要用于 一对多 的依赖关系,当 被观察者(Subject) 发生变化时,它会通知所有 观察者(Observers) 进行相应的更新。
一般来说,观察者模式包含以下角色:
-
Subject(被观察者,通常是一个单例或全局对象)
- 维护一组观察者(通常是一个
std::vector
或std::list
)。 - 提供注册(
attach
)、移除(detach
)和通知(notify
)观察者的方法。
- 维护一组观察者(通常是一个
-
Observer(观察者,通常是一个接口或基类)
- 定义一个
update()
方法,所有观察者必须实现该方法,以便在被观察者状态变化时被调用。
- 定义一个
-
具体观察者(Concrete Observer)
- 继承
Observer
接口,实现update()
方法。 - 当
Subject
发生变化时,ConcreteObserver
负责做出响应。
- 继承
典型的 C++ 观察者模式实现
#include <iostream>
#include <vector>
#include <memory>
// 观察者接口(Observer)
class Observer {
public:
virtual ~Observer() = default;
virtual void update(int data) = 0; // 观察者需要实现的更新方法
};
// 被观察者(Subject)
class Subject {
public:
void attach(std::shared_ptr<Observer> observer) {
observers_.push_back(observer);
}
void detach(std::shared_ptr<Observer> observer) {
observers_.erase(std::remove(observers_.begin(), observers_.end(), observer), observers_.end());
}
void notify(int data) {
for (auto& observer : observers_) {
observer->update(data); // 依次通知所有观察者
}
}
private:
std::vector<std::shared_ptr<Observer>> observers_; // 存储所有观察者
};
// 具体观察者(ConcreteObserver)
class ConcreteObserver : public Observer {
public:
ConcreteObserver(std::string name) : name_(name) {}
void update(int data) override {
std::cout << "Observer " << name_ << " received update: " << data << std::endl;
}
private:
std::string name_;
};
int main() {
auto subject = std::make_shared<Subject>();
auto observer1 = std::make_shared<ConcreteObserver>("A");
auto observer2 = std::make_shared<ConcreteObserver>("B");
subject->attach(observer1);
subject->attach(observer2);
std::cout << "Notifying observers with data 42:" << std::endl;
subject->notify(42); // 触发通知
subject->detach(observer1);
std::cout << "Notifying observers with data 99 after detaching Observer A:" << std::endl;
subject->notify(99); // 只剩 Observer B 会收到通知
return 0;
}
补充你的理解
你提到的 “观察者模式一般有一个基类的单例”,在某些情况下是对的,但并 不一定非要是单例模式:
- 单例模式(Singleton) 和 观察者模式(Observer) 是两种不同的设计模式,它们可以结合使用,但观察者模式本身 并不要求被观察者必须是单例。
- 只有在某些情况下,比如 全局日志管理器、事件管理器,才会使用 单例模式 来确保只有一个
Subject
存在。
观察者模式 VS 回调
在你的 Acceptor
代码中:
void set_new_connection_callback(std::function<void(int)> const &callback);
这里的 回调函数(callback)也可以用于事件通知,但它只是 一个函数指针,而 观察者模式允许多个对象同时监听变化,更加灵活。
总结
✅ 你的理解是正确的,但可以更精确地表述:
- 观察者模式是一个一对多的通知机制,当 被观察者 发生变化时,它会通知所有 观察者。
- 被观察者(Subject)通常有一个接口来管理多个观察者(
attach
、detach
、notify
)。 - 观察者(Observer)是一个接口或抽象类,具体观察者(ConcreteObserver)继承并实现
update()
方法。 - 单例模式(Singleton)和观察者模式是独立的,Subject 不一定是单例。
- 回调机制(callback)是另一种常见的通知方式,但通常是“一对一”的,而观察者模式是“一对多”的。
策略模式:
定义一系列的算法,把他们一个个封装起来,并且使他们可以互相替换。该模式算法可独立使用它的客户程序。
稳定点:客户程序算法的调用关系
设计原则:接口隔离原则----类与类之间的依赖只建立在简单的接口上面。
两种方法:1.采用具体的接口选择算法 2.依赖注入
扩展代码:
是的,你对 策略模式(Strategy Pattern) 的理解基本正确!策略模式的核心思想是 将算法或行为封装成独立的类,并通过接口指针(或引用)在运行时动态切换算法。
策略模式的关键点
- 策略接口(Strategy Interface)
- 定义一组可互换的算法或行为。
- 具体策略(Concrete Strategy)
- 实现不同的算法,继承策略接口。
- 环境类(Context)
- 持有一个策略的指针(基类指针或
std::unique_ptr
),可以动态设置或切换策略,并对外暴露一个统一的接口。
- 持有一个策略的指针(基类指针或
策略模式的典型 C++ 实现
#include <iostream>
#include <memory>
// 1. 策略接口
class Strategy {
public:
virtual ~Strategy() = default;
virtual void execute() const = 0;
};
// 2. 具体策略A
class ConcreteStrategyA : public Strategy {
public:
void execute() const override {
std::cout << "执行策略 A\n";
}
};
// 3. 具体策略B
class ConcreteStrategyB : public Strategy {
public:
void execute() const override {
std::cout << "执行策略 B\n";
}
};
// 4. 上下文类,持有策略对象
class Context {
public:
explicit Context(std::unique_ptr<Strategy> strategy)
: strategy_(std::move(strategy)) {}
void setStrategy(std::unique_ptr<Strategy> strategy) {
strategy_ = std::move(strategy);
}
void executeStrategy() const {
if (strategy_) {
strategy_->execute();
}
}
private:
std::unique_ptr<Strategy> strategy_;
};
// 5. 测试策略模式
int main() {
// 使用策略 A
Context context(std::make_unique<ConcreteStrategyA>());
context.executeStrategy();
// 切换为策略 B
context.setStrategy(std::make_unique<ConcreteStrategyB>());
context.executeStrategy();
return 0;
}
你的理解总结
✅ "策略模式:就是在一个类中封装了多种算法进行调用" → 对的,不同策略可以封装不同的算法,实现可扩展的行为。
✅ "这个类中会有一个接口可以说是这些算法的基类指针" → 对的,策略模式通常使用 基类指针或智能指针(如 std::unique_ptr
) 来存储和调用具体策略对象。
✅ "通过该指针去调用这些算法" → 对的,Context
通过 持有策略基类指针,在运行时可以动态切换策略并调用。
策略模式的优点
- 符合开闭原则(OCP):可以新增新策略而不改动已有代码。
- 提高代码复用性:不同的策略可以在不同环境下复用。
- 消除冗长的
if-else
语句:将多个不同的行为封装到独立的策略类中,使代码更加清晰。
策略模式的应用场景
- 日志记录(不同的日志输出策略:文件、控制台、远程服务器)
- 压缩算法(支持不同的压缩格式:ZIP、RAR、GZIP)
- 支付系统(支持不同的支付方式:支付宝、微信、信用卡)
- AI 机器人决策(不同的决策策略)
- 游戏中的 NPC 行为(不同的 AI 计算策略)