设计模式的基础概念和分类
设计模式:针对不同问题,对接口编程
23种设计模式可分为三类:创建者模式、结构型模式、行为模式
创建者模式有:简单工厂模式、抽象工厂模式。
设计模式原则:
1、开闭原则(对扩展开发、修改关闭)
2、里氏代换
3、依赖倒装
4、接口隔离原则(使用多个接口、降低耦合度)
5、合成复用原则
6、迪米特法则
简单工厂
概念
简单工厂模式主要解决接口选择问题.,它通过一个工厂类根据传入的参数来创建不同类型的对象,而无需向客户端暴露创建逻辑。
角色说明
-
Factory(工厂):负责创建产品对象的静态方法
-
Product(抽象产品):定义产品的接口
-
ConcreteProduct(具体产品):实现产品接口的具体类
核心代码:子类执行。
一个抽象父类,多个接口 ,通过参数的传递到一个工厂中,生成对应的产品。
注重接口统一,通过同类产品,得出不同型号的对象
代码举例
#include <iostream>
using namespace std;
class hamburger
{
public:
virtual void thisname() = 0;
hamburger()
{
cout << "汉堡构造函数" << endl;
}
~hamburger()
{
cout << "汉堡析构函数" << endl;
}
};
class beefhamburger :public hamburger
{
public:
void thisname()
{
cout << "牛肉堡" << endl;
}
};
class chickenhamburger :public hamburger
{
public:
void thisname()
{
cout << "鸡肉堡" << endl;
}
};
class shrimphamburger :public hamburger
{
public:
void thisname()
{
cout << "鲜虾堡" << endl;
}
};
class KFC {
public:
hamburger* creatahabao(string name)
{
if (name == "牛肉")
{
return new beefhamburger;
}
else if (name == "鸡肉")
{
return new chickenhamburger;
}
else if (name == "虾")
{
return new shrimphamburger;
}
else
{
return nullptr;
}
}
};
int main()
{
KFC* shop = new KFC();//唯一工厂
hamburger* habo;//具有不同种类
habo = shop->creatahabao("牛肉");//选择牛肉堡,让工厂制作
habo->thisname();//得到牛肉堡
delete habo;
habo = shop->creatahabao("鸡肉");//选择鸡肉堡,让工厂制作
habo->thisname();//得到鸡肉堡
delete habo;
delete shop;
}
抽象工厂模式
概念
多个抽象角色时使用的一种工厂模式,给客户端接口,再不指定产品的具体情况下,创建多个产品族的产品对象。多用于一组产品,且产品种类多,多个抽象产品类。
在模式中,客户端不再负责对象的创建,把责任给具体的工厂类,客户端只负责对对象的调用,从而明确各个类的职责。
角色说明
抽象工厂模式有四个角色:抽象工厂角色、具体工厂角色、抽象产品角色、具体产品角色
代码举例
实现不同系统下的文件读写功能
#include <iostream>
#include<memory>
using namespace std;
//产品类
class FileReader {
public:
virtual void Readuseage() = 0;
FileReader() = default;
virtual ~FileReader() = default;
};
class FileWriter {
public:
virtual ~FileWriter() = default; // 重要!
virtual void Writeuseage() = 0;
FileWriter() = default;
};
class WinFileReader :public FileReader {
public:
void Readuseage()override
{
cout << "进行windows的读取"<<endl;
}
};
class WinFileWriter :public FileWriter {
public:
void Writeuseage()override {
cout << "进行windows的写入" << endl;
}
};
class LinuxFileReader :public FileReader {
public:
void Readuseage()override
{
cout << "进行Linux的读取"<<endl;
}
};
class LinuxFileWriter :public FileWriter {
public:
void Writeuseage()override {
cout << "进行Linux的写入" << endl;
}
};
class MacOsFileReader :public FileReader {
public:
void Readuseage()override
{
cout << "进行MacOS的读取"<<endl;
}
};
class MacOsFileWriter :public FileWriter {
public:
void Writeuseage()override {
cout << "进行MacOS的写入" << endl;
}
};
//多家工厂
class FileFactory {
public:
virtual ~FileFactory() = default; // 重要!
virtual unique_ptr<FileReader> Reader() = 0;
virtual unique_ptr<FileWriter> Writer() = 0;
FileFactory() = default;
};
class WinFileFactory :public FileFactory {
public:
unique_ptr<FileReader> Reader()override {
return make_unique<WinFileReader>();
}
unique_ptr<FileWriter> Writer()override {
return make_unique<WinFileWriter>();
}
};
class LinuxFileFactory :public FileFactory {
public:
unique_ptr<FileReader> Reader()override {
return make_unique<LinuxFileReader>();
}
unique_ptr<FileWriter> Writer()override {
return make_unique<LinuxFileWriter>();
}
};
class MacOsFileFactory :public FileFactory {
public:
unique_ptr<FileReader> Reader()override {
return make_unique<MacOsFileReader>();
}
unique_ptr<FileWriter> Writer()override {
return make_unique<MacOsFileWriter>();
}
};
class ClientSystem
{public:
unique_ptr<FileFactory> select(string name)
{
if (name == "Win")
{
return make_unique<WinFileFactory>();
}
else if (name == "Linux")
{
return make_unique<LinuxFileFactory>();
}
else if (name == "macOS")
{
return make_unique<MacOsFileFactory>();
}
else
{
return nullptr;
}
}
};
int main()
{
auto client = make_unique<ClientSystem>();
auto system = client->select("Win");//选择一个工厂
auto reader=system->Reader();//得到属于这个工厂的套餐,并取出
auto writer=system->Writer();
reader->Readuseage();
writer->Writeuseage();
auto system2 = client->select("Linux");
auto reader2 = system2->Reader();//得到属于这个工厂的套餐,并取出
auto writer2 = system2->Writer();
reader2->Readuseage();
writer2->Writeuseage();
}
优点:当一个套餐包含多个产品组被设计成对象,能保证客户端只使用一个产品组的套餐的。
而这个产品只需要初始化一次就可以使用了,客户端可以分离这个套餐。适用
缺点:不易扩展,加产品时要更改很多地方
简单工厂处理单一产品的多类型 问题,比如一个汉堡工厂生产各种口味的汉堡。抽象工厂处理多产品的多品牌问题,比如不同快餐品牌生产各自特色的汉堡、炸鸡、饮料套餐。"=
原型模型
概念
它是创建,复制运行时的对象和对象各个成员的值。解决在运行期建立和删除原型
用一个已有的对象复制创建出新的对象。类似于复制一辆已经造好的样办车,现在根据客户需求做修改。
优点:性能提高,避免构造函数的约束,
缺点:配备一个
应用场景:
1.创建需要高成本的对象(对象的创建需要连接数据库、读取大文件、进行复制计算)
2.需要创建相似的对象
3.避免复杂的配置过程(初始化配置)
4.一个对象多个修改者的场景
5.与工厂方法结合出现
角色
1、抽象原型:定义克隆方法的接口
2、具体原型:对原型的内部进行定义
拷贝原型创建新对象

额外知识点
克隆的两种方式
浅拷贝(Shallow Copy)
-
只复制对象本身,不复制对象引用的其他对象
-
相当于"复制指针",新旧对象共享同一份数据
-
问题:修改一个对象会影响另一个对象
深拷贝(Deep Copy)
-
复制对象及其引用的所有对象
-
创建完全独立的新对象
-
真正的原型模式应该使用深拷贝
QObject的限制
- QT中的QObject有一个重要特性:禁止拷贝构造。这是因为:
- QObject有父子关系,拷贝会导致关系混乱
- QObject有信号槽连接,拷贝无法正确处理
与拷贝构造的区别
-
设计意图不同
-
拷贝构造 是C++语言的基础机制
-
目的是创建一个对象的副本
-
是语言级别的功能
-
关注的是"如何复制"
-
原型模式 是设计模式
-
目的是通过复制来创建新对象,避免昂贵的初始化
-
是架构级别的设计思想
-
关注的是"为什么要复制"和"什么时候复制"
拷贝构造函数被调用的场景:
1.用已知对象初始化一个正在创建的对象
2.函数形式参数为对象的时候,实参对象行形参对象传递
3.函数返回值为对象,需要被获取时。
2.抽象层次不同
原型模式的核心实现机制式拷贝构造
拷贝构造式具体的实现细节
原型模式提供了抽象接口
编译时多态性:通过重载函数、运算符重载
运行时多态性:虚函数和继承实现
代码举例
#include <iostream>
using namespace std;
class prototype {
public:
prototype(int a, int b, int c)
{
x = a;
y = b;
z = new int(c);
cout << "构造函数" <<"x="<<x<<"y="<<y<<"*z="<<*z <<endl;
}
prototype(const prototype& other) //标准拷贝构造函数的样式
{
z = new int(*(other.z));
x = other.x;
y = other.y;
cout << "拷贝构造" << "x=" << x << "y=" << y << "*z=" << *z << endl;
}
prototype clone()
{
cout << "克隆" << endl;
return *this;//调用拷贝构造函数
}
~prototype()
{
if (z) {//防止多次delete
cout << "析构函数 *z=" << *z << endl;
delete z;
}
else {
cout << "析构函数 z=nullptr" << endl;
}
}
void print() const {
cout << "x=" << x << " y=" << y << " *z=" << (z ? *z : 0) << endl;
}
private:
int x;
int y;
int* z;
};
int main()
{
prototype p(1, 2, 3);
prototype p2 = p.clone();
}
建造者模式
概念
建造者模式是一种创建型设计式,它将一个复杂的对象的构进过程与它的表示分离;使同样的构建过程可以创建同的表示
,核心思想:将复杂的对象的构造过程解成多个简单的步骤,通过指导者按顺序进行分配建造者执行,获得最终成型的对象
结构图

角色说明
建造者模式包含4个核心角色:
-
产品(Product):要构建的复杂对象
-
抽象建造者(Builder):定义构建产品的各个步骤的接口
-
具体建造者(Concrete Builder):实现构建步骤,提供产品的具体实现
-
指挥者(Director):控制构建过程,按特定顺序调用建造者的方法
代码举例
#include<iostream>
#include"product.h"
using namespace std;
class ComputerBuilder {
public:
virtual ~ComputerBuilder() = default;
virtual void buildCPU() = 0;
virtual void buildMemory() = 0;
virtual void buildGPU() = 0;
virtual Computer getResult() = 0;
};
class GameComputerBuilder :public ComputerBuilder {
public:
GameComputerBuilder()
{
gamecomputer = new Computer();
}
virtual void buildCPU()
{
gamecomputer->setCPU("Intel 5600");
}
virtual void buildMemory()
{
gamecomputer->setMemory("32GB");
}
virtual void buildGPU()
{
gamecomputer->setGpu("5060Ti");
}
Computer getResult()
{
return *gamecomputer;
}
virtual ~GameComputerBuilder()
{
delete gamecomputer;
}
private:
Computer* gamecomputer;
};
class OfficeComputerBuilder :public ComputerBuilder {
public:
OfficeComputerBuilder()
{
officecomputer = new Computer();
}
virtual void buildCPU()
{
officecomputer->setCPU("Intel Core i5-12400");
}
virtual void buildMemory()
{
officecomputer->setMemory("8GB");
}
virtual void buildGPU()
{
officecomputer->setGpu("AMD Radeon RX 570");
}
Computer getResult()
{
return *officecomputer;
}
virtual ~OfficeComputerBuilder()
{
delete officecomputer;
}
private:
Computer* officecomputer;
};
头文件:设置电话类:摄像头成员、电池、屏幕成员对象。输入成员对象的值的函数,输出成员对象的函数。建造类:电话所带配件的抽象类,然后用不同品牌的手机创建类,去实现抽象类的成员函数。
源文件:实现电成 辁员函数:输入和输出函数
单例模式
概念
在一个类当中,只实例化出一个,所有调用个类实例化的对象都属于同一个。
优点:节省资源.提高效率
代码举例
饿汉模式:在程序开始后就实例化出对象
#include <iostream>
#include <string>
class EagerSingleton {
private:
// 🎯 1. 私有构造函数:防止外部创建实例
EagerSingleton() {
std::cout << "🔼 饿汉式单例:立即创建实例" << std::endl;
}
// 🎯 2. 禁用拷贝构造和赋值操作
EagerSingleton(const EagerSingleton&) = delete;
EagerSingleton& operator=(const EagerSingleton&) = delete;
// 🎯 3. 静态成员变量:在程序开始时即创建
static EagerSingleton instance;
public:
// 🎯 4. 公有静态方法:获取唯一实例
static EagerSingleton& getInstance() {
return instance;
}
// 业务方法
void doSomething(const std::string& task) {
std::cout << "饿汉单例执行: " << task << std::endl;
}
// 🎯 5. 获取实例地址(用于验证)
void showAddress() const {
std::cout << "饿汉实例地址: " << this << std::endl;
}
};
// 🚀 关键:在类外定义并初始化静态成员(程序启动时就创建)
EagerSingleton EagerSingleton::instance;
懒汉模式:等需要实例化再进行
#include <iostream>
#include <string>
class LazySingleton {
private:
// 🎯 1. 私有构造函数
LazySingleton() {
std::cout << "😴 懒汉式单例:第一次调用时创建实例" << std::endl;
}
// 🎯 2. 禁用拷贝构造和赋值操作
LazySingleton(const LazySingleton&) = delete;
LazySingleton& operator=(const LazySingleton&) = delete;
// 🎯 3. 静态指针:初始为nullptr
static LazySingleton* instance;
public:
// 🎯 4. 公有静态方法:第一次调用时创建实例
static LazySingleton* getInstance() {
if (instance == nullptr) {
instance = new LazySingleton(); // 🚨 非线程安全!
}
return instance;
}
// 业务方法
void doSomething(const std::string& task) {
std::cout << "懒汉单例执行: " << task << std::endl;
}
void showAddress() const {
std::cout << "懒汉实例地址: " << this << std::endl;
}
// 🎯 5. 手动释放资源(可选)
static void destroyInstance() {
if (instance != nullptr) {
delete instance;
instance = nullptr;
std::cout << "🗑️ 懒汉实例已销毁" << std::endl;
}
}
};
// 🚀 关键:静态指针初始化为空
LazySingleton* LazySingleton::instance = nullptr;
适配器模式
概念
一个存在的对象要和另一个进行关联,但不适配,需要将目标对象进行设置适配器,即在原对象上加上那个存在对象的实例。作为两个不兼容的接口之间的桥梁。它属于结构体型模式,结合两个独立接口的功能。解决在系统软件当种,将一些现存对象放到新的环境种,而新环境要求的接口是现对象不能满足的
优点
可以让任何两个没有关联的类一起执行,为了提高类的利用:增加类的透明度;灵活性好
缺点
设配器适用过多,让整个系统非常零乱,不容易整体进行把控。
目前的问题:怎么把两个不兼容的类,绑定在一起,然后这两个不兼容的类是什么样的。
代码举例
#include <iostream>
#include <string>
// 🎯 目标接口:美式插座 (Target)
class AmericanSocket {
public:
virtual void supplyPower() const {
std::cout << "🔌 美式插座:提供110V交流电" << std::endl;
}
virtual ~AmericanSocket() = default;
};
// 🎯 被适配者:欧洲插头 (Adaptee)
class EuropeanPlug {
public:
void requirePower() const {
std::cout << "🇪🇺 欧洲插头:需要220V交流电" << std::endl;
}
void specificEuropeanFeature() const {
std::cout << "💡 欧洲插头特有功能:接地保护" << std::endl;
}
};
// 🎯 适配器:电源转接头 (Adapter)
class PowerAdapter : public AmericanSocket {
private:
EuropeanPlug* europeanPlug_; // 🎯 组合被适配对象
public:
PowerAdapter(EuropeanPlug* plug) : europeanPlug_(plug) {}
void supplyPower() const override {
std::cout << "🔄 电源适配器工作:" << std::endl;
europeanPlug_->requirePower();
std::cout << " ⚡ 转换:110V → 220V" << std::endl;
std::cout << " ✅ 适配完成!" << std::endl;
europeanPlug_->specificEuropeanFeature(); // 🎯 保持原有功能
}
~PowerAdapter() {
delete europeanPlug_;
}
};
关键点:
-
接口不兼容 :
NewLogger和OldLogger就像美式插座和欧式插头 -
适配器桥梁 :
LoggerAdapter就像电源转接头 -
成功协作:通过适配器,不兼容的双方能够一起工作
桥接模式
概念
桥接模式是将抽象部分和实现部分分离,让它们可以独立地变化和实现,在组合替代继承,非常的灵活性,还有扩展性特别好。
优点:分离抽象类
缺点:增加系统的难度
能够识别出独立变化
应用场景
当一个类,内部具备多种变化维度,使用这个方法可以解耦这些变化维度,使高层代码架构稳定,当一个类存在两个独立变化的维度,这两个维度都需要进行扩展时,
当一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性时
当一个系统不希望适用继承或多层次继承导致系统类的个数几句增加时
角色说明
|-------------------------|------------------------|------------------------|
| Abstraction | RemoteControl | 定义抽象接口,维护Implementor引用 |
| RefinedAbstraction | BasicRemote | 扩展抽象接口,实现具体业务 |
| Implementor | Device | 定义实现类的接口 |
| ConcreteImplementor | xiaomiTv, huaweiTv | 具体实现 |
代码举例
同一个遥控器可以控制不同品牌的电视
#include <iostream>
using namespace std;
class Device {//实现者
private:
bool powered = false;
public:
virtual ~Device() = default;
virtual void powerOn() = 0;
virtual void powerOff() = 0;
virtual bool ispower() {
return powered;
}
protected:
void setpower(bool powered_)
{
powered = powered_;
}
};
class xiaomiTv:public Device
{
public:
void powerOn()
{
setpower(true);
cout << "打开小米电视" << endl;
}
void powerOff()
{
setpower(false);
cout << "关闭小米电视" << endl;
}
};
class huaweiTv :public Device
{
public:
void powerOn()
{
setpower(true);
cout << "打开华为电视" << endl;
}
void powerOff()
{
setpower(false);
cout << "关闭华为电视" << endl;
}
};
class RemoteControl {
protected:
Device* device;
public:
RemoteControl(Device* dev) :device(dev)
{}
virtual ~RemoteControl() = default;
virtual void togglePower() = 0;
};
class BasicRemote :public RemoteControl {
public:
BasicRemote(Device* dev) : RemoteControl(dev) {}
void togglePower()
{
if (device->ispower() == false)
{
device->powerOn();
}
else
{
device->powerOff();
}
}
};
int main()
{
xiaomiTv xiaomi;
huaweiTv huawei;
unique_ptr<BasicRemote> br=make_unique<BasicRemote>(&xiaomi);
br->togglePower();
br = make_unique<BasicRemote>(&huawei);
br->togglePower();
}
组合实体模式
概念
将对组合成熟性结构使得用户对下单个对象和组合对象的使用具有一致性。
优点:统一组合对象和叶子对象更容易扩展新功能
成员说明
| 角色 | 对应类 | 职责 | 特点 |
|---|---|---|---|
| Component | menu | 声明统一接口 | 抽象类,纯虚函数 |
| Leaf | menuitem | 叶子节点实现 | final,不能被继承 |
| Composite | menugroups | 组合节点实现 | 可以包含子组件 |
#include<iostream>
#include<vector>
#include<memory>
using namespace std;
using namespace std;
class menu {
public:
virtual ~menu() = default;
virtual void price() const = 0;
};
class MenuItem : public menu {
private:
int myprice;
string name;
public:
MenuItem(int x,string n) : myprice(x),name(n) {}
void price()const override {
cout <<name<< "价格:" <<myprice<< "\t"<< "会员8折优惠" << endl;;
}
};
class MenuGroups :public menu
{
private:
vector<shared_ptr<menu>> menus;//子节点组
string name;//菜单组名
public:
MenuGroups(string nm) :name(nm) {}
void price()const override {
cout << "菜单名:" << name << "\t菜的个数" << menus.size() << endl;
cout << name << "菜品包含:" << endl;
for (auto e : menus)
{
e->price();
}
}
void add(shared_ptr<menu>newmenu)
{
menus.push_back(newmenu);
}
void remove(shared_ptr<menu>oldmenu)
{
auto it = find(menus.begin(),menus.end(), oldmenu);
if (it != menus.end())
{
menus.erase(it);
}
}
};
int main()
{
auto fish1 = make_shared<MenuItem>(10,"清蒸鱼");
auto fish2 = make_shared<MenuItem>(15,"红烧鱼");
auto beef1 = make_shared<MenuItem>(20,"泡椒牛肉");
auto beef2 = make_shared<MenuItem>(20,"红烧牛肉");
auto soup1 = make_shared<MenuItem>(10, "番茄鸡蛋汤");
auto group1 = make_shared<MenuGroups>("饭店菜单");
auto group2 = make_shared<MenuGroups>("热菜菜单");
auto group3 = make_shared<MenuGroups>("汤菜菜单");
group1->add(fish1);
group1->add(beef1);
group1->add(group2);
group2->add(beef2);
group2->add(fish2);
group1->add(group3);
group3->add(soup1);
group1->price();
}
装饰器模式
概念
包装模式,给对象添加一些额外的职责,装饰器模式比子类更为灵活。允许动态地 向一个对象添加新的功能,而不改变其结构。它通过创建一系列包装器来扩展对象的功能。
核心思想:用包装代替继承
| 角色 | 职责 | 类比 |
|---|---|---|
| Component(组件) | 定义对象的接口 | 咖啡接口 |
| ConcreteComponent(具体组件) | 实现基本功能 | 基础咖啡 |
| Decorator(装饰器) | 持有组件引用,定义装饰接口 | 调料抽象类 |
| ConcreteDecorator(具体装饰器) | 实现具体的装饰功能 | 牛奶、糖等具体调料 |
优点:比继承更加灵活,继承静态,而它是动态
缺点:它会产生很多粒度对象
代码举例
class coffee {//
public:
virtual ~coffee() = default;
virtual void order()=0 ;// ✅ 纯虚函数,不需要实现
virtual int getprice()=0;
};
class Espresso :public coffee
{public:
void order() {//具体组件
cout << "浓缩咖啡" << "--";
}
int getprice()
{
return myprice;
}
private:
int myprice = 25;
};
class Americano :public coffee
{
public:
void order() {
cout << "美式咖啡" << "--";
}
int getprice()
{
return myprice;
}
private:
int myprice = 20;
};
class Latte :public coffee
{
public:
void order() {
cout << "拿铁" << "--";
}
int getprice()
{
return myprice;
}
private:
int myprice = 25;
};
class CoffeeDecorator :public coffee//装饰器
{
protected:
shared_ptr<coffee> component;
public:
CoffeeDecorator(shared_ptr<coffee>co):component(co){}
void order()
{
if (component)
{
component->order();
}
}
int getprice(int x)
{
if (component) {
return component->getprice();
}
return 0;
}
};
class SugarDecorator :public CoffeeDecorator {
public:
SugarDecorator(shared_ptr<coffee> co) :CoffeeDecorator(co) {}
void order()
{
if (component)
component->order();
cout << "加糖";
}
int getprice()
{
if (component) {
return component->getprice()+2;
}
return 0.0;
}
};
class MilkDecorator :public CoffeeDecorator {
public:
MilkDecorator(shared_ptr<coffee> co) :CoffeeDecorator(co) {}
void order()
{
if (component)
component->order();
cout <<"-- "<<"加牛奶";
}
int getprice()
{
if (component) {
return component->getprice() +5;
}
return 0.0;
}
};
int main()
{
auto newcoffee = make_shared<SugarDecorator>(make_shared<Americano>());
auto newcoffee2 = make_shared< MilkDecorator>(newcoffee);
newcoffee->order();
cout << newcoffee->getprice() << endl;
newcoffee2->order();
cout << newcoffee2->getprice() << endl;
}
代码实现遇到的问题:
-
❌ 接口设计:纯虚函数没有正确声明
-
❌ 装饰器实现:没有添加自己的功能
-
❌ 价格计算:缺少装饰器的价格累加
-
❌ 语法错误:对象创建语法不正确
外观模式
概念
为子系统的一组接口 提供一个统一的接口,该模式定义了一个高层接口,该模式定义了一个高层接口,这个高层接口能使子系统更加容易使用。并且外观模式可以解决层结构分离、降低系统耦合度和为新旧系统交互提供接口功能
核心思想:
"简化复杂性":通过一个统一的接口来隐藏子系统的复杂性,让客户端只需要与这个简单接口交互。
角色说明
|-----------------------|-----------|------------------|-----------------|
| 外观角色 (Facade) | 提供简化的统一接口 | ComputerFacade | 知道哪些子系统负责处理请求 |
| 子系统角色 (Subsystem) | 实现具体功能 | CPU, Memory等 | 完成实际工作,不知道外观存在 |
| 客户端 (Client) | 通过外观使用系统 | main()函数 | 只与外观交互,不直接接触子系统 |
代码举例
#include <iostream>
using namespace std;
class LightingSystem {
public:
void turnOn()
{
cout << "打开电灯"<<endl;
}
void turnOff()
{
cout << "关闭电灯" << endl;
}
};
class AirConditioning {
public:
void setTemperature(int temp)
{
cout << "设置空调温度" <<temp<< endl;
}
void setMode(const string& mode)
{
cout << "当前模式:" << mode << endl;
}
};
class Curtain {
public:
void openCuratin(){
cout << "打开窗帘" << endl;
}
void closeCurtain()
{
cout << "关闭窗帘" << endl;
}
};
class SmartHomeFacade {
public:
virtual ~SmartHomeFacade() = default;
virtual void leaveHome() = 0; // 离家模式
virtual void returnHome() = 0; // 回家模式
};
class SmartHomeFacadeImpl :public SmartHomeFacade
{
unique_ptr<AirConditioning> airCd;
unique_ptr<Curtain> ct;
unique_ptr<LightingSystem> ls;
public:
SmartHomeFacadeImpl() {
airCd = make_unique<AirConditioning>();
ct = make_unique<Curtain>();
ls = make_unique < LightingSystem >();
}
virtual void leaveHome()
{
ct->closeCurtain();
ls->turnOff();
}
virtual void returnHome() // 回家模式
{
ct->openCuratin();
ls->turnOn();
airCd->setTemperature(26);
}
};
// ... 其他子系统
int main()
{
SmartHomeFacadeImpl myhome;
myhome.returnHome();
}
享元模式
概念
享元模式的本质 :通过分离内部状态(共享)和外部状态(不共享),在保持对象功能完整性的前提下,大幅减少内存中对象的数量。
优点:
缺点:提高了内部复杂度,不能随内部变化而变化
角色说明
Flyweight:享元接口,通过此接口可以接受并作用于外部状态
ConcreteFlyweight:具体的享元实现对象,必须是可共享的,需要封装享元接口的内部状态。
UnsharedConcreteFlyweight:非共享的享元实现对象,并不是所有的享元对象都需要共享。非共享享元对象的作用:作为模式的"安全阀",确保在需要独特性的场景下,仍然能够使用相同的接口,保持设计的灵活性和一致性。
FlyweightFactory:享元工厂,主要用来创建并且管理共享的享元对象,并对外提供访问共享享元接口
Client:享元客户端,主要的工作是维护一个Flayweight的引用,计算或存储享元对象的外部状态。
非共享享元对象 vs 共享享元对象
| 特性 | 共享享元对象 (ConcreteFlyweight) | 非共享享元对象 (UnsharedConcreteFlyweight) |
|---|---|---|
| 创建方式 | 通过工厂缓存,相同内部状态只创建一次 | 每次请求都创建新对象 |
| 内存使用 | 高效,避免重复对象 | 可能占用更多内存 |
| 适用场景 | 内部状态相同,只有外部状态不同 | 每个对象都有独特数据 |
| 生命周期 | 由工厂管理,长期存在 | 由客户端管理,临时使用 |
| 使用目的 | 优化内存,提高性能 | 处理特殊情况,保持灵活性 |
享元模式的真正价值
1. 解决核心问题:对象数量爆炸
-
问题:系统需要创建大量相似对象
-
症状:内存占用过高、GC压力大、性能下降
-
解决方案:共享不变的部分,分离变化的部分
代码举例
#include <iostream>
#include<unordered_map>
#include<string>
#include<memory>
//享元模式用于游戏武器系统
using namespace std;
class Weapon
{
public:
virtual ~Weapon() = default;
virtual void displayInfo() = 0;
};
class NormalWeapon :public Weapon {
private:
string name;//武器名
int AttackSpeed;//攻击速度
int BaseDamage;//基础伤害
public:
NormalWeapon(string n, int speed, int damage) :name(n), AttackSpeed(speed), BaseDamage(damage)
{
cout << "构造出基础武器" << endl;
}
void displayInfo()
{
cout << "武器的信息:" << endl;
cout << "武器名:" << name << "攻击速度:" << AttackSpeed << "伤害:" << BaseDamage<<endl;
}
};
class SpecialWeapon :public Weapon
{
private:
int Durability;//武器耐久度
string name;//武器名
string usage;//武器作用
public:
SpecialWeapon(int d, string n, string u) :Durability(d), name(n), usage(u) {
cout << "构造出特殊武器" << endl;
}
void displayInfo()
{
cout << "武器的信息:" << endl;
cout << "武器名:" << name << "武器耐久度:" << Durability << "作用:" << usage << endl;
}
};
class WeaponFactory
{private:
unordered_map < string, shared_ptr<Weapon>> weapons;
public:
WeaponFactory()
{
}
shared_ptr<Weapon> getWeapon(string n, int a, int s)
{
//根据属性和名字组合设置为键
string key = n + "-" + to_string(a);
//查看是否以及有这个装备
auto it = weapons.find(key);
if (it != weapons.end()) {
cout << "✓ 从对象池获取已存在的Circle: " << key << endl;
return it->second; // 返回已存在的对象
}
cout << "✎ 创建新的装备并加入装备池: " << key << endl;
auto w = make_shared<NormalWeapon>(n, a, s);
weapons.insert(make_pair(key, w));
return w;
}
shared_ptr<Weapon> getUniqueWeapon(int a, string n,string u)
{
return make_shared<SpecialWeapon>(a, n, u);
}
void displayInfo()
{
for (auto e : weapons)
{
e.second->displayInfo();
}
}
};
//客户端
class Document {
private:
WeaponFactory& factory;
public:
Document(WeaponFactory& f) : factory(f) {}
void displayWeapons()
{
cout << "显示当前的所有武器:" << endl;
factory.getWeapon("青龙刀", 90, 5);
factory.getWeapon("青钢剑", 85, 7);
factory.getWeapon("火炮", 100, 2);
factory.displayInfo();
auto uniquew= factory.getUniqueWeapon(100, "麻痹药", "麻痹");
uniquew->displayInfo();
//获取武器信息
}
};
int main()
{
WeaponFactory f;
Document d(f);
d.displayWeapons();
}
代理模式
概念
为其它对象提供一种代理以控制这个对象的访问。一个类代表另一个类的功能。结构型模式
通俗解释:真实对象=明星,代理对象=经纪人(控制访问,可额外添加功能) 客户端=合作方(通过经纪人与明星交互)
应用场景:优化接口的性能。需求传给代理,代理传给客户端。将客户端与目标对象分离。
核心思想:在不改变真实对象的情况下,通过代理层控制访问,添加额外功能。
优点和缺点:职责非常清晰,高扩展性,高智能。造成请求的处理速度慢,实现慢,因为对象变多了。
角色说明
-
代理模式三大角色:
-
Image:抽象接口 -
RealImage:真实对象(昂贵操作) -
ImageProxy:代理对象(控制访问)
-
-
代理的核心价值:
-
延迟加载:需要时才创建真实对象
-
访问控制:添加额外功能(如日志记录)
-
透明性:客户端使用方式不变
-
-
关键设计思想:
-
代理与真实对象实现相同接口
-
代理持有对真实对象的引用
-
代理在适当时候才创建真实对象
-
代码举例
class File {
public:
virtual ~File() = default;
virtual void readFile() = 0;//显示图片
virtual string getFilename() = 0;//获取文件名
};
class RealFile :public File//真实对象
{
private:
string filename;
void load()
{
cout << "开始加载文件....." << filename << endl;
cout << "加载文件成功" << endl;
}
public:
RealFile(string& file) :filename(file) {
load();//真是对象创建时的加载
};
void readFile()override {
cout << "读取文件:" << filename << endl;
}
string getFilename() override
{
return filename;
}
};
class FileProxy :public File {
private:
string filename;
unique_ptr<RealFile> file;
int accessCount = 0; // 添加访问次数统计
string username;//用户名
public:
FileProxy(const string& file,const string& name) :filename(file),username(name)
{
cout << "创建文件代理:" << filename << endl;
}
bool checkUser()//检查用户名来决定是否可以访问
{
if (username == "adm")
{
return true;
}
else
{
return false;
}
}
void readFile()override {
if (!checkUser())
{
cout << "当前用户不能访问" << endl;
return ;
}
accessCount++;
cout << "代理受到客户端请求,开始联系对象" << endl;
file = make_unique<RealFile>(filename);
cout << "文件加载和创建成功" << endl;
cout << "显示文件内容" << endl;
file->readFile();
}
string getFilename() override { // 实现获取文件名
return filename; // 返回文件名
}
//代理特有方法
bool isFileLoaded() const { // 检查图片是否已加载
return file != nullptr; // 如果指针不为空,说明已加载
}
void getCount()
{
cout << "当前文件访问次数"<<accessCount << endl;
}
};
int main()
{ //客户端请求
FileProxy proxy1("文件1","s");
cout << "photo1是否已加载: " << (proxy1.isFileLoaded() ? "是" : "否") << endl;//否
cout << "客户端申请查看图片给代理" << endl;
cout << "\n--- 第一次显示图片 ---" << endl;
proxy1.readFile(); // 第一次显示,会加载真实图片
cout << "photo1是否已加载: " << (proxy1.isFileLoaded() ? "是" : "否") << endl;//是
proxy1.readFile();
proxy1.readFile();
proxy1.getCount();
FileProxy proxy2("文件1", "adm");
proxy2.readFile();
}
责任链模式
概念
避免请求发送者与接收者耦合在一起,让多个对象都有机会处理请求,将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。
角色说明
| 角色 | 作用 | 现实类比 |
|---|---|---|
| Handler(抽象处理者) | 定义处理请求的接口,包含后继链接 | 审批人的抽象标准 |
| ConcreteHandler(具体处理者) | 具体处理请求的类,可以访问后继者 | 具体的审批人(组长、经理等) |
| Client(客户端) | 创建责任链,向链头发起请求 | 提交申请的员工 |
| Request(请求) | 封装请求信息 | 请假申请单 |
客户端 → 处理者A → 处理者B → 处理者C → ... → 处理完成
↓ ↓ ↓
处理 转发 处理
代码举例
应用场景:相似审批请假流程
#include <iostream>
#include<string>
#include<memory>
using namespace std;
class Handler
{
public:
virtual ~Handler() = default;
virtual void handleRequest(int day) = 0;
};
class BaseHandler :public Handler
{private:
shared_ptr<Handler> pnext;
public:
BaseHandler( ) :pnext(nullptr) {}
void linkNext(shared_ptr<Handler> next)
{
pnext = next;
}
void handleRequest(int days) override {
// 基础类不实现具体逻辑,由子类实现
}
protected:
void passNext(int days)
{
if (pnext)
{
pnext->handleRequest(days);
}
else
{
cout << "没有更高权限的处理者,请假 " << days << " 天被拒绝" << endl;
}
}
};
class TeacherHandler : public BaseHandler {
private:
int Max_day = 3;
public:
void handleRequest(int days) override {
if (days <= Max_day)
{
cout << "班主任处理请假天数:" << days;
}
else
{
cout << "班主任处理不了这个请假天数,转给下一级领导" << endl;
passNext(days);
}
}
};
class DirectorHandler : public BaseHandler {
private:
int Max_day = 7;
public:
void handleRequest(int days) override {
if (days <= Max_day)
{
cout << "教导主任处理请假天数:" << days;
}
else
{
cout << "教主任处理不了这个请假天数,转给下一级领导" << endl;
passNext(days);
}
}
};
class PrincipalHandler : public BaseHandler {
private:
int Max_day = 30;
public:
void handleRequest(int days) override {
if (days <= Max_day)
{
cout << "校长处理请假天数:" << days;
}
else
{
cout << "校长处理不了这个请假天数,转给下一级领导" << endl;
passNext(days);
}
}
};
int main()
{
shared_ptr<TeacherHandler > handler1 = make_shared< TeacherHandler >();
shared_ptr<DirectorHandler > handler2 = make_shared< DirectorHandler>();
shared_ptr<PrincipalHandler> handler3 = make_shared< PrincipalHandler>();
handler1->linkNext(handler2);
handler2->linkNext(handler3);
handler1->handleRequest(50);
}
最初错误的代码:
#include <iostream>
#include<string>
#include<memory>
using namespace std;
class Handler
{
public:
virtual ~Handler() = default;
virtual void HandleTask(int day) = 0;
};
class ConcreteHandler :public Handler
{private:
shared_ptr<ConcreteHandler> pnext;
string name;
public:
ConcreteHandler( string n) : name(n)
{
}
void linkNext(shared_ptr<ConcreteHandler> next)
{
pnext = next;
}
void HandleTask(int day)
{
if (name == "班主任")
{
if (day <= 3)
{
cout << "班主任批准假期,假期天数:" << day << endl;
}
else
{
pnext->HandleTask(day);
}
}
else if (name == "教导主任")
{
if (day <=7)
{
cout << "教导主任批准假期,假期天数:" << day << endl;
}
else
{
pnext->HandleTask(day);
}
}
else if (name == "校长")
{
if (day <=30)
{
cout << "校长批准假期,假期天数:" << day << endl;
}
else
{
cout << "假期太长不批准" << endl;
}
}
}
};
int main()
{
shared_ptr<ConcreteHandler> handler1 = make_shared< ConcreteHandler>("班主任");
shared_ptr<ConcreteHandler> handler2 = make_shared< ConcreteHandler>("教导主任");
shared_ptr<ConcreteHandler> handler3 = make_shared< ConcreteHandler>("校长");
handler1->linkNext(handler2);
handler2->linkNext(handler3);
handler1->HandleTask(10);
}
问题:
问题1:违反开闭原则
所有处理逻辑都写在同一个类中,通过if-else判断
问题2:潜在的空指针风险
没有检查pnext是否为空就调用
问题3:不够面向对象
应该为每种处理者创建独立的类
中介者模式
概念
用中介对象来封装一系列的对象,然后中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互,并且通过中介者就可以实现它们之间的交互了。
角色说明
| 角色 | 作用 | 现实类比 |
|---|---|---|
| Mediator(抽象中介者) | 定义同事对象交互的接口 | 消息中心的协议 |
| ConcreteMediator(具体中介者) | 协调各同事对象,知道所有同事 | 具体的消息中心 |
| Colleague(抽象同事类) | 定义同事类的接口,持有中介者引用 | 部门的基本规范 |
| ConcreteColleague(具体同事类) | 实现同事类,只与中介者通信 | 具体的部门 |
代码举例
前置声明飞机类
抽象中介者-塔台接口
前置声明飞机类
class Airplane;
class ControlTower {//确保中介者都有相同的工作方式,但是塔台不能只有一个
public:
virtual ~ControlTower() = default;
virtual void sendMessage(const string& message, const string& from, const string& to) = 0; // 转发消息
virtual void registerAirplane(shared_ptr<Airplane> airplane) = 0; // 添加飞机到这个聊天室
};
//抽象同事类-飞机基类
class Airplane {
protected:
shared_ptr<ControlTower> tower; // 每个飞机都持有塔台的引用
string flightNumber; // 航班号
public:
Airplane(shared_ptr<ControlTower> t, const string& number)
: tower(t), flightNumber(number) {
} // 构造函数初始化塔台和航班号
virtual ~Airplane() = default; // 虚析构函数
virtual void send(const string& message, const string& to) = 0; // 发送消息到塔台
virtual void receive(const string& message, const string& from) = 0; // 接收塔台的转发消息
string getFlightNumber() const { // 获取航班号
return flightNumber;
}
};
class AirportTower :public ControlTower {
private:
vector < shared_ptr<Airplane>> airplanes;//当前塔台的飞机数
public:
virtual void sendMessage(const string& message, const string& from, const string& to) // 转发消息
{
if (to == "ALL")
{
cout << "消息发给所有航班" << endl;
for (auto e : airplanes)//发给所有航班
{
if (e->getFlightNumber() != from) { // 排除发送者自己
e->receive(message, from);
}
}
}
else {
for (auto e : airplanes)//发给所有航班
{
if (e->getFlightNumber() == to)
{
cout << "找到需要接收消息的飞机:" << to << endl;
e->receive(message,from);
return;
}
}
cout << "没有找到需要接收消息的飞机" << endl;
}
}
virtual void registerAirplane(shared_ptr<Airplane> airplane) // 添加飞机到这个聊天室
{
airplanes.push_back(airplane);
cout << "塔台注册: 航班 " << airplane->getFlightNumber() << endl; // 输出注册信息
}
};
class PassengerPlane :public Airplane {
public:
PassengerPlane(string number, shared_ptr<ControlTower> tower) :Airplane(tower,number)
{
}
virtual void send(const string& message, const string& to)
{
cout << "客机发送消息到塔台,让塔台转发给:" << to << endl;
tower->sendMessage(message, this->getFlightNumber(), to);
}
virtual void receive(const string& message, const string& from) // 接收塔台的转发消息
{
cout << "客机编号:" << this->getFlightNumber();
cout << "接收塔台传来的消息" << "\t";
cout << "发送客机的编号: " << from << " 消息:" << message << endl;
}
};
int main()
{
//创建塔台
cout << "创建一个新塔台" << endl;
shared_ptr<AirportTower> newtower = make_shared<AirportTower>();
cout << "创建几架客机到塔台" << endl;
shared_ptr< PassengerPlane> plane1 = make_shared< PassengerPlane>("0001",newtower);
shared_ptr< PassengerPlane> plane2 = make_shared< PassengerPlane>("0002", newtower);
shared_ptr< PassengerPlane> plane3 = make_shared< PassengerPlane>("0003", newtower);
cout << "塔台注册这几架客机到聊天室" << endl;
newtower->registerAirplane(plane1);
newtower->registerAirplane(plane2);
newtower->registerAirplane(plane3);
cout << "开始进行互发消息" << endl;
plane1->send("你回家吃法吗?", "0002");
plane2->send("我不回家吃饭了", "ALL");
}
策略模式
本质:定义一系列算法,将算法封装起来,它们直接可以相互替换,它们的底层实现不一样,但目的是一样,但是需要根据客户的需求选择对应的算法。
核心思想:将算法与实现分离。
解决问题:
1.通过多态的方式消除条件语句
2.同一个算法可以在多个地方使用
3.便于扩展,并且不影响已有代码
4.算法独立
代码举例
#include <iostream>
#include <string>
#include <memory>
using namespace std;
//1.抽象策略类 -支付策略接口
class PaymentStrategy {
public:
virtual ~PaymentStrategy() = default;
virtual void pay(double amount) = 0;//进行支付
virtual string getPayName() = 0;//获取当前支付策略名
};
class AlipayStrategy :public PaymentStrategy {
public:
void pay(double amount) {
cout << "进行支付宝支付:" << amount << "元";
}
string getPayName()
{
return "支付宝支付";
}
};
class WechatPayStrategy :public PaymentStrategy {
public:
void pay(double amount) {
cout << "进行微信支付:" << amount << "元";
}
string getPayName()
{
return "微信支付";
}
};
class BankCardStrategy :public PaymentStrategy {
public:
void pay(double amount) {
cout << "进行银行卡支付:" << amount << "元";
}
string getPayName()
{
return "银行卡支付";
}
};
class PaymentContext {
private:
shared_ptr<PaymentStrategy> strategy;//持有策略引用
public:
void setStrategy(shared_ptr<PaymentStrategy> newStrategy) {
strategy = newStrategy; // 动态切换算法
}
void executePay(int amount)//进行支付
{
strategy->pay(amount);
}
};
int main()
{
//列出支付算法对象
shared_ptr<AlipayStrategy> alipay = make_shared<AlipayStrategy>();
shared_ptr<BankCardStrategy> bankcard = make_shared<BankCardStrategy>();
shared_ptr<WechatPayStrategy> wechatpay= make_shared<WechatPayStrategy>();
//环境类-支付上下文
PaymentContext p;
p.setStrategy(alipay);
p.executePay(100);
//切换支付策略
p.setStrategy(bankcard);
p.executePay(100);
}
模板模式
概念
模板方法模式:定义一个操作中的算法骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
解决的问题:
-
代码复用:公共算法逻辑在父类中实现
-
扩展性好:子类可以重写特定步骤而不改变算法结构
-
控制反转:父类控制流程,子类提供具体实现
-
符合开闭原则:对扩展开放,对修改关闭
代码举例
#include <iostream> // 引入输入输出流库
#include <string> // 引入字符串库
#include <vector> // 引入向量库
#include <memory> // 引入智能指针库
using namespace std; // 使用标准命名空间
// 1. 抽象模板类 - 角色创建器
class CharacterCreator { // 定义角色创建的抽象模板类
public:
// 模板方法 - 定义角色创建的算法骨架
void createCharacter() { // 角色创建的主流程(建议添加final关键字)
displayCreationProcess(); // 步骤1:显示创建过程
slectProfession(); // 步骤2:选择职业(由子类实现)
slectAttributes(); // 步骤3:选择属性(由子类实现)
slectequipment(); // 步骤4:选择装备(由子类实现)
displayCharacterInfo(); // 步骤5:显示角色信息
}
protected:
string profession; // 角色职业
string attributes; // 角色属性
string equipment; // 角色装备
// 抽象方法 - 由子类实现具体逻辑
virtual void slectProfession() = 0; // 纯虚函数:选择职业
virtual void slectAttributes() = 0; // 纯虚函数:选择属性
virtual void slectequipment() = 0; // 纯虚函数:选择装备
// 具体方法 - 显示创建过程(所有子类共享)
void displayCreationProcess() {
cout << "=== 角色创建过程 ===" << endl; // 输出创建过程标题
}
// 具体方法 - 显示角色信息(所有子类共享)
void displayCharacterInfo() {
cout << "=== 角色信息 ===" << endl; // 输出角色信息标题
cout << "职业:" << profession << endl; // 显示职业信息
cout << "属性:" << attributes << endl; // 显示属性信息
cout << "装备:" << equipment << endl; // 显示装备信息
cout << "==================" << endl; // 输出分隔线
}
};
// 2. 具体类 - 战士创建器
class WarriorCreator : public CharacterCreator { // 实现战士角色创建
protected:
void slectProfession() override { // 实现选择职业方法
profession = "战士"; // 设置职业为战士
cout << "🛡️ 选择了战士职业" << endl; // 输出职业选择信息
}
void slectAttributes() override { // 实现选择属性方法
attributes = "力量:90, 体力:80, 敏捷:60"; // 设置战士属性
cout << "💪 分配了战士属性: " << attributes << endl; // 输出属性分配信息
}
void slectequipment() override { // 实现选择装备方法
equipment = "巨剑, 重甲, 盾牌"; // 设置战士装备
cout << "⚔️ 装备了战士装备: " << equipment << endl; // 输出装备信息
}
};
// 3. 具体类 - 刺客创建器
class stabberCreator : public CharacterCreator { // 实现刺客角色创建
protected:
void slectProfession() override { // 实现选择职业方法
profession = "刺客"; // 设置职业为刺客
cout << "🗡️ 选择了刺客职业" << endl; // 输出职业选择信息
}
void slectAttributes() override { // 实现选择属性方法
attributes = "力量:60, 体力:70, 敏捷:95"; // 设置刺客属性
cout << "🏃 分配了刺客属性: " << attributes << endl; // 输出属性分配信息
}
void slectequipment() override { // 实现选择装备方法
equipment = "匕首, 皮甲, 毒药"; // 设置刺客装备
cout << "🕶️ 装备了刺客装备: " << equipment << endl; // 输出装备信息
}
};
// 4. 具体类 - 法师创建器
class MageCreator : public CharacterCreator { // 实现法师角色创建
protected:
void slectProfession() override { // 实现选择职业方法
profession = "法师"; // 设置职业为法师
cout << "🔮 选择了法师职业" << endl; // 输出职业选择信息
}
void slectAttributes() override { // 实现选择属性方法
attributes = "力量:40, 体力:50, 智力:95"; // 设置法师属性
cout << "📚 分配了法师属性: " << attributes << endl; // 输出属性分配信息
}
void slectequipment() override { // 实现选择装备方法
equipment = "法杖, 法袍, 魔法书"; // 设置法师装备
cout << "✨ 装备了法师装备: " << equipment << endl; // 输出装备信息
}
};
int main() {
cout << "=== 模板方法模式演示 - 游戏角色创建系统 ===\n" << endl; // 输出程序标题
// 创建战士角色
cout << "【创建战士角色】" << endl; // 输出创建战士提示
CharacterCreator* warrior = new WarriorCreator(); // 创建战士角色对象
warrior->createCharacter(); // 调用模板方法创建战士
delete warrior; // 释放战士对象内存
cout << endl; // 输出空行
// 创建刺客角色
cout << "【创建刺客角色】" << endl; // 输出创建刺客提示
CharacterCreator* stabber = new stabberCreator(); // 创建刺客角色对象
stabber->createCharacter(); // 调用模板方法创建刺客
delete stabber; // 释放刺客对象内存
cout << endl; // 输出空行
// 创建法师角色
cout << "【创建法师角色】" << endl; // 输出创建法师提示
CharacterCreator* mage = new MageCreator(); // 创建法师角色对象
mage->createCharacter(); // 调用模板方法创建法师
delete mage; // 释放法师对象内存
// 使用智能指针的版本(推荐)
cout << "\n=== 使用智能指针版本 ===" << endl; // 输出智能指针版本标题
auto smartWarrior = make_unique<WarriorCreator>(); // 使用智能指针创建战士
smartWarrior->createCharacter(); // 调用模板方法创建战士
return 0; // 程序正常结束
}
状态模式
概念
允许一个对象在其内部状态改变它的行为,看起来似乎修改了类。属于行为型模式
案例:一个篮球运动员在不同比赛阶段的状态变化
-
热身状态:简单投篮,保存体力
-
正式比赛状态:全力进攻,激烈对抗
-
受伤状态:暂停比赛,接受治疗
-
休息状态:场下观战,恢复体力
context定义客户感兴趣的接口,同时维护一个具体处理当前状态的实例对象
state:状态接口
con:具体实现状态的类,每个类实现上下文相关的状态
优点:简化逻辑控制,更好分离状态和行为,更好扩展,更好装药转换
缺点:一个状态对应状态处理类,会使程序引入太多状态变得混乱
本质:根据状态来分离和选择行为
状态模式的核心要点
1.状态封装:每个状态封装特定行为
2.状态转换:由上下文控制或状态间协作
3.行为委托:上下文将请求委托给当前状态
4.开闭原则:新增状态不影响现有代码
代码举例
定义一个环境:定义一个状态接口指针(获取处理状态的实例),状态转换应该由上下文控制 或状态间协作,因此这个环境的作用是为了状态转换。
状态接口:构造函数: 析构函数: 纯虚函数(处理上下文状态的函数),状态的执行方法虚函数
多个具体处理状态的行为类(继承状态接口):在对应环境中处理方法的函数。
class Light;
//1.状态接口
class LightState {
public:
virtual ~LightState() = default;
virtual void turnOn(Light* light)=0;
virtual void turnOff(Light* light) = 0;
virtual string getStateName()const = 0;
};
class OffState :public LightState {
public:
void turnOn(Light* light);
void turnOff(Light* light);
string getStateName()const;
};
class OnState : public LightState {
public:
void turnOn(Light* light) override;
void turnOff(Light* light) override;
std::string getStateName() const override;
};
class Light
{
private:
shared_ptr<LightState> currentSate_;
string location_;//电灯位置
public:
Light(const string location) :location_(location) {
currentSate_ = make_shared<OffState>();
}
void setState(shared_ptr<LightState> newState)
{
if (!newState) {
cerr << "❌ 错误:尝试设置空状态" << endl;
return;
}
cout << "原本状态:" << currentSate_->getStateName() << "转换为" << newState->getStateName() << endl;
currentSate_ = newState;
}
void turnOn()
{
cout << "打开电灯" << endl;
currentSate_->turnOn(this);
}
void turnOff()
{
cout << "关闭电灯" << endl;
currentSate_->turnOff(this);
}
};
void OffState::turnOn(Light* light)
{
shared_ptr<OnState> on = make_shared<OnState>();
light->setState(on);
cout << "电灯已打开" << endl;
}
void OffState::turnOff(Light* light)
{
cout << "电灯处于关闭" << endl;
}
string OffState::getStateName() const
{
return "关闭状态";
}
void OnState::turnOn(Light* light)
{
cout << "电灯处于打开中" << endl;
}
void OnState::turnOff(Light* light)
{
shared_ptr<OffState> off = make_shared<OffState>();
light->setState(off);
cout << "电灯已关闭" << endl;
}
std::string OnState::getStateName() const
{
return "打开状态";
}
int main()
{
Light l("客厅");
l.turnOn();
l.turnOn();
l.turnOff();
}
观察者模式
概念
一对多的依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都得到通知自动更新,观察者和目标分离,动态联动机制。
角色说明
目标对象:一个目标可以被多个观察者观察,目标发生改变通知观察者
观察者接口:通过参数传递或回调机制获取更新数据
具体目标实现对象:维护目标状态和维护观察者的业务逻辑。
观察者的具体实现对象:
优点:实现观察者与目标之间的抽象耦合(目标不用知道观察者的具体实现),动态联动(随时添加和删除新的观察者),支持广播通信(一次变化所有的观察者都能够知道),开闭原则(新增观察者类型无需修改目标)
缺点:性能开销(所有观察者都会因为目标更改被调用),观察者执行顺序不可控,内存泄漏风险(观察者中对于目标)
观察者的本质:触发联动
代码举例
应用:温度检测
#include <iostream>
#include<vector>
#include<memory>
#include<string>
using namespace std;
//1.观察者接口
class TemperatureObserver {
public:
virtual ~TemperatureObserver() = default;
virtual void update(double temperature) = 0;
virtual string getName()const = 0;
};
//2.目标接口
class TemperatureSubject {
public:
virtual ~TemperatureSubject() = default;
virtual void attach(shared_ptr<TemperatureObserver> observer) = 0;//添加观察者
virtual void detach(shared_ptr<TemperatureObserver> observer) = 0;//删除观察者
virtual void notify(double temperture) = 0;//更新温度后通知观察者
};
//3.目标:温度传感器
class TemperatureSensor : public TemperatureSubject
{private:
vector< shared_ptr<TemperatureObserver>>observers;
double currenttemperature_;
public:
virtual void attach(shared_ptr<TemperatureObserver> observer) //添加观察者
{ if(!observer)
{
cout << "观察者不存在" << endl;
return;
}
cout << "添加新的监控者" <<observer->getName()<< endl;
observers.push_back(observer);
}
virtual void detach(shared_ptr<TemperatureObserver> observer) //删除观察者
{
if (!observer) {
cerr << "❌ 错误:尝试移除空观察者"<< endl;
return;
}
// 修正:按名称查找,而不是指针值
auto it = remove_if(observers.begin(), observers.end(),
[&observer](const shared_ptr<TemperatureObserver>& obs) {
return obs->getName() == observer->getName();
});
if (it != observers.end()) {
observers.erase(it, observers.end());
cout << "🚫 " << observer->getName() << " 停止监控 " << endl;
}
else {
cout << "⚠️ " << observer->getName() << " 未找到在 " << endl;
}
}
virtual void notify(double temperture) //更新温度后通知观察者
{
if (observers.empty()) {
cout << " 没有观察者" << endl;
return;
}
for (auto e : observers)
{
e->update(temperture);
}
}
void setNewTemp(double newtemp)
{
if (currenttemperature_ == newtemp) {
return; // 温度未变化,不通知
}
cout << " 温度: "
<< currenttemperature_ << "°C → " << newtemp << "°C" << endl;
currenttemperature_ = newtemp;
notify(newtemp);
}
double getCurrentTemperature() const {
return currenttemperature_;
}
};
class ConsoleAlarm : public TemperatureObserver
{private:
string alarmName_;
double alarmThreshold_;
public:
ConsoleAlarm(const string& name, double threshold=50)
: alarmName_(name), alarmThreshold_(threshold) {
}
virtual void update(double temperature)
{
cout << "📟 " << alarmName_ << " 收到温度: " << temperature << "°C" << endl;
if (temperature < alarmThreshold_)
{
cout << "当前的温度属于标准温度,表示正常" << endl;
}
else
{
cout << "温度超标"<< alarmName_<<"开始报警!!!!" << endl;
}
}
virtual string getName()const
{
return alarmName_;
}
};
class Logger : public TemperatureObserver
{private:
string LoggerName_;
vector<double> temperatures;
public:
Logger(const string& name) : LoggerName_(name){}
virtual void update(double temperature)
{
cout << "📟 " << LoggerName_ << " 收到温度,开始记录 " << temperature << "°C" << endl;
temperatures.push_back(temperature);
}
virtual string getName()const
{
return LoggerName_;
}
void printLog()
{
cout << "开始打印,发生改变的温度各数值:" << endl;
for (auto e : temperatures)
{
cout<< e << "°C" << endl;
}
}
};
int main()
{
auto sensor = make_shared<TemperatureSensor>();
shared_ptr<ConsoleAlarm> Csa = make_shared<ConsoleAlarm>("室内温度报警器",40);
shared_ptr<ConsoleAlarm> Csa2 = make_shared<ConsoleAlarm>("室外温度报警器", 50);
shared_ptr<Logger> Log1 = make_shared<Logger>("温度改变记录器");
sensor->attach(Csa);
sensor->attach(Csa2);
sensor->attach(Log1);
sensor->setNewTemp(40);
sensor->setNewTemp(50);
sensor->setNewTemp(100);
Log1->printLog();
}
备忘录模式
概念:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可以将对象恢复到原先保存的状态。
优点:更好的封装性,简化原发器(备忘录对象被保存在原发器之外,由用户来操作),宅接口和宽接口(宅接口保证只有原发器可以访问备忘录)
缺点:导致比较高的开销(因为备忘录是缓存,如果数据大就有很大开销)
角色说明
1.原发器:创建备忘录+从备忘录恢复数据
2.备忘录:存储原发器的数据
3.备忘录管理者:保存和管理备忘录对象
核心思想:宽接口(备忘录只有原发器可以访问内部) 窄接口(对外部只提供描述)
应用场景
- 需要撤销和重做的场景
- 需要保存对象状态的场景
- 状态数据不太大的场景
代码举例
#include <iostream>
#include<memory>
#include<string>
#include<stack>
using namespace std;
//1.备忘录
class TextMemento {
private:
friend class TextEditor;
//宽接口
string content;//备忘录记录的内容
//私有构造函数,只有有友元类可以创建
TextMemento(const string& text) : content(text) {}
public:
//窄接口:只提供描述
string getscription()
{
return "文字长度:" + to_string(content.length());
}
//
};
//原发器:文本编辑器
class TextEditor {
private:
string content_;
public:
TextEditor():content_(""){}
//创建备忘录对象
// const成员函数,不允许修改任何数据成员
shared_ptr<TextMemento> createMemento()
{
return shared_ptr<TextMemento>(new TextMemento (content_));
}
//从备忘录恢复
void restoreFromMemento(shared_ptr<TextMemento> memento)
{
content_ = memento->content;
}
//添加文本
void addContent(string text)
{
cout << "📝 添加文本: " << text << endl;
content_ += text;
}
//显示当前内容
void display()const
{
cout << "当前内容: " << content_ << endl;
}
};
class HistoryManager {
public:
stack<shared_ptr<TextMemento>> undoStack_;
stack<shared_ptr<TextMemento>> redoStack_;
const int MAX_HISTORY = 5;
public:
void saveState(shared_ptr<TextMemento> memento) {
// TODO: 保存到撤销栈,管理栈大小
if (undoStack_.size() < 5)
{
undoStack_.push(memento);
}
else
{
cout << "撤销栈满了,无法进行撤销" << endl;
}
}
shared_ptr<TextMemento> undo() {
// TODO: 从撤销栈弹出,压入重做栈
shared_ptr<TextMemento> memeto = undoStack_.top();
undoStack_.pop();
redoStack_.push(memeto);
return memeto;
}
// 重做
shared_ptr<TextMemento> redo() {
// TODO: 从重做栈弹出,压入撤销栈
shared_ptr<TextMemento> memeto = redoStack_.top();
redoStack_.pop();
undoStack_.push(memeto);
return memeto;
}
bool canUndo() const {
return !undoStack_.empty();
}
// 检查是否可以重做
bool canRedo() const {
return !redoStack_.empty();
}
};
int main()
{
shared_ptr< TextEditor> editor = make_shared< TextEditor>();
editor->addContent(string("hellow"));
editor->display();
HistoryManager history;
history.saveState(editor->createMemento());
editor->addContent(" World");
history.saveState(editor->createMemento());
editor->display();
editor->addContent("!");
history.saveState(editor->createMemento());
editor->display();
cout << "\n--- 测试撤销功能 ---" << endl;
if (history.canUndo()) {
auto memento = history.undo();
editor->restoreFromMemento(memento);
editor->display();
}
// 再次撤销
if (history.canUndo()) {
auto memento = history.undo();
editor->restoreFromMemento(memento);
editor->display();
}
// 再次撤销
if (history.canUndo()) {
auto memento = history.undo();
editor->restoreFromMemento(memento);
editor->display();
}
if (history.canRedo()) {
auto memento = history.redo();
editor->restoreFromMemento(memento);
editor->display();
}
if (history.canRedo()) {
auto memento = history.redo();
editor->restoreFromMemento(memento);
editor->display();
}
if (history.canRedo()) {
auto memento = history.redo();
editor->restoreFromMemento(memento);
editor->display();
}
}
命令模式
概念
将一个请求封装成一个对象,从而可以使用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。
角色说明

生活比喻:想象你在餐厅点餐
-
客户(Client) → 创建订单
-
服务员(Invoker) → 接收并传递订单
-
厨师(Receiver) → 执行具体烹饪
-
订单(Command) → 封装了具体的烹饪请求
代码举例
#include <iostream>
#include <memory>
#include <vector>
#include <string>
#include <unordered_map>
// 🎯 角色1:接收者 (Receiver) - 厨师,知道如何执行具体操作
class Chef {
public:
void cookPasta() {
std::cout << "👨🍳 厨师:正在烹饪意大利面..." << std::endl;
}
void cookSteak() {
std::cout << "👨🍳 厨师:正在煎牛排..." << std::endl;
}
void prepareSalad() {
std::cout << "👨🍳 厨师:正在准备沙拉..." << std::endl;
}
void makeDessert() {
std::cout << "👨🍳 厨师:正在制作甜点..." << std::endl;
}
};
// 🎯 角色2:命令接口 (Command) - 订单抽象
class Order {
public:
virtual ~Order() = default;
virtual void execute() = 0; // 🎯 执行订单
virtual std::string getName() const = 0; // 获取菜品名称
};
// 🎯 角色3:具体命令 (Concrete Command) - 具体订单
class PastaOrder : public Order {
private:
std::shared_ptr<Chef> chef_; // 🎯 绑定接收者
public:
PastaOrder(std::shared_ptr<Chef> chef) : chef_(chef) {}
void execute() override {
chef_->cookPasta(); // 🎯 委托给接收者执行
}
std::string getName() const override {
return "意大利面";
}
};
class SteakOrder : public Order {
private:
std::shared_ptr<Chef> chef_;
public:
SteakOrder(std::shared_ptr<Chef> chef) : chef_(chef) {}
void execute() override {
chef_->cookSteak();
}
std::string getName() const override {
return "牛排";
}
};
class SaladOrder : public Order {
private:
std::shared_ptr<Chef> chef_;
public:
SaladOrder(std::shared_ptr<Chef> chef) : chef_(chef) {}
void execute() override {
chef_->prepareSalad();
}
std::string getName() const override {
return "沙拉";
}
};
class DessertOrder : public Order {
private:
std::shared_ptr<Chef> chef_;
public:
DessertOrder(std::shared_ptr<Chef> chef) : chef_(chef) {}
void execute() override {
chef_->makeDessert();
}
std::string getName() const override {
return "甜点";
}
};
// 🎯 角色4:调用者 (Invoker) - 服务员,负责接收和传递订单
class Waiter {
private:
std::vector<std::shared_ptr<Order>> orders_; // 🎯 订单队列
public:
// 🎯 接收订单
void takeOrder(std::shared_ptr<Order> order) {
orders_.push_back(order);
std::cout << "💁 服务员:收到 " << order->getName() << " 订单" << std::endl;
}
// 🎯 取消最后一个订单
void cancelLastOrder() {
if (!orders_.empty()) {
auto order = orders_.back();
std::cout << "❌ 服务员:取消 " << order->getName() << " 订单" << std::endl;
orders_.pop_back();
}
}
// 🎯 提交所有订单给厨房
void submitOrders() {
std::cout << "\n📋 服务员:提交 " << orders_.size() << " 个订单给厨房" << std::endl;
std::cout << "=================================" << std::endl;
for (const auto& order : orders_) {
std::cout << "⬇️ 处理: " << order->getName() << std::endl;
order->execute(); // 🎯 执行命令
}
orders_.clear();
std::cout << "✅ 所有订单处理完成!" << std::endl;
}
// 🎯 显示当前订单状态
void showOrders() const {
std::cout << "\n📊 当前订单队列 (" << orders_.size() << "个):" << std::endl;
for (size_t i = 0; i < orders_.size(); ++i) {
std::cout << " " << (i + 1) << ". " << orders_[i]->getName() << std::endl;
}
}
};
// 🎯 角色5:客户端 (Client) - 顾客,创建具体命令
class Customer {
public:
void placeOrder(Waiter& waiter, std::shared_ptr<Order> order) {
std::cout << "👤 顾客:点了一份 " << order->getName() << std::endl;
waiter.takeOrder(order);
}
};
访问者模式
概念
表示一个作业与某对象结构的各元素的操作。在不改变个元素的前提下定义作用于这些元素的新操作。
客户端-访问接口(visit方法)-具体访问实现对象(实现每个抽象访问者)-被访问元素接口-具体元素实现对象-对象结构(包含多个被访问对象,让访问者访问它的结构,通常为一个集合)
访问者本质:预留通路,回调实现。
优点:扩展性好,复用性好(通过访问者,可以定义多个的通用功能),分离无关行为
缺点:破坏封装(需要访问部件的内部结构),对象结构变化困难(如果新增部件,需要修改所有访问者接口和实现)
角色说明
访问者(体验中心)-带着各种检查设备。 被访问元素(体验者)-不同的人需要不同的检查。访问接口(体检流程)-统一的检查入口
代码举例
#include <iostream>
#include<vector>
#include<memory>
#include <string> // 🔴 缺少string头文件
using namespace std;
class MalePatient;
class FemalePatient;
class ChildPatient;
//访问者接口
class MedicalVisitor {
public:
virtual ~MedicalVisitor() = default;
virtual void visit( MalePatient* patient) = 0;//检查男性
virtual void visit( FemalePatient* patient) = 0;//检查女性
virtual void visit( ChildPatient* patient) = 0;//检查儿童
};
//被访问元素接口(体验者标准接口)
class Patient {
public:
virtual ~Patient() = default;
virtual void accept(MedicalVisitor* visitor) = 0;//预留访问通路
virtual string getName() = 0;
};
class MalePatient :public Patient {
private:
string name_;
public:
MalePatient(const string name) {
name_ = name;
cout << "男性患者" << endl;
}
void accept(MedicalVisitor* visitor)
{
visitor->visit(this);
}
virtual string getName()
{
return name_;
}
};
class FemalePatient :public Patient {
private:
string name_;
public:
FemalePatient(const string name) {
name_ = name;
cout << "女性患者" << endl;
}
void accept(MedicalVisitor* visitor)
{
visitor->visit(this);
}
virtual string getName()
{
return name_;
}
};
class ChildPatient :public Patient {
private:
string name_;
public:
ChildPatient(const string name) {
name_ = name;
cout << "儿童患者" << endl;
}
void accept(MedicalVisitor* visitor)
{
visitor->visit(this);
}
virtual string getName()
{
return name_;
}
};
class BloodPressureVisitor :public MedicalVisitor {
public:
virtual void visit( MalePatient* patient) //检查男性
{
cout << "检查男性血压 --" << "姓名: ";
cout << patient->getName() << endl;
}
virtual void visit( FemalePatient* patient) //检查女性
{
cout << "检查女性血压 --" << "姓名: ";
cout << patient->getName() << endl;
}
virtual void visit( ChildPatient* patient) //检查儿童
{
cout << "检查儿童血压 --" << "姓名: ";
cout << patient->getName() << endl;
}
};
class UltrasoundVisitor :public MedicalVisitor {
public:
virtual void visit(MalePatient* patient) //检查男性
{
cout << "超声波检查 - 男性" << endl;
cout << patient->getName() << endl;
}
virtual void visit(FemalePatient* patient) //检查女性
{
cout << "超声波检查 - 女性" << endl;
cout << patient->getName() << endl;
}
virtual void visit( ChildPatient* patient) //检查儿童
{
cout << "超声波检查 - 儿童" << endl;
cout << patient->getName() << endl;
}
};
class MedicalCenter {
private:
vector<unique_ptr<Patient>> patients;
public:
void addPatient(unique_ptr<Patient>patient)
{
patients.push_back(move(patient));//unique_ptr 不能被拷贝,只能被移动在容器中使用时,必须使用 std::move()
}
void conductExamination(MedicalVisitor* visitor)
{
cout << "开始体检" << endl;
for (auto& e : patients)
{
e->accept(visitor);
}
cout << "体检结束" << endl;
}
};
int main()
{
MedicalCenter center;
center.addPatient(make_unique<MalePatient>("张三"));
center.addPatient(make_unique<FemalePatient>("王芳"));
center.addPatient(make_unique<ChildPatient>("小李"));
UltrasoundVisitor vs;
center.conductExamination(&vs);
}
解释器模式
概念
给定一个语言,定义它的文法表示,并定义一个解释器,这个解释器使用该标识来解释语言中的句子。该模式通过语言中的每个语法规则表示为一个类,使得语言的语法可以用面向对象的方式来表示和执行。
核心思想:
文法表示:将语言的语法规则抽象为类层次结构
解释执行:通过递归的方式遍历语法树执行具体操作
分离关注点:语法定义域执行逻辑相互独立
角色说明
模式结构

核心组件:
1.抽象表达式接口:定义解释操作的统一接口,通常包含interpret(context)方法,是所有语法规则类的基类。
2.终结符表达式:代表语言中的基本元素(叶子节点),实现简单的解释逻辑。
3.非终结符表达式:代表语言中的符合结构(非叶子节点,而是一个小型的树),包含其它表达式,通过递归调用实现解释
4.上下文环境:存储解释器需要的全局信息,提供数据,在解释过程中传递状态信息。
5.客户端:构建表达式语法树,创建上下文环境,调用解释器执行解释操作。
工作流程:
1.定义文法:将目标语言的语法规则抽象成类结构
2.构建语法树:根据输入语句创建对象的表达式对象树
3.设置上下文:准备解释需要的环境数据
4.递归解释:从根节点开始,递归调用个节点的解释方法
5.返回结果
优点:容易扩展新的语法,用于实现语法,
缺点:不适合复杂语法,解释器模式会引起膨胀
遇到的问题:
上下文的实际作用
// ❌ 糟糕的设计:变量值硬编码在表达式中
class BadVariableExpression : public BooleanExpression {
private:
string name_;
bool hardcodedValue_; // 🔴 问题:值被固定了!
public:
BadVariableExpression(const string& name) : name_(name) {
// 🔴 问题:表达式创建时就固定了值,无法动态改变
if (name == "A") hardcodedValue_ = true;
else if (name == "B") hardcodedValue_ = false;
else hardcodedValue_ = false;
}
bool interpret(/* 没有上下文 */) const override {
return hardcodedValue_; // 🔴 总是返回固定值
}
};
// ❌ 使用问题:
// 同一个表达式 "A" 在不同场景下应该有不同的值
// 但这里永远返回 true,无法适应变化
解释器模式本质:分离实现,解释执行
代码举例
案例:计算器
//抽象表达式接口
class Expression {
public:
virtual ~Expression() = default;
virtual double interpret(unordered_map<string,double> var) = 0;//解释方法
};
//终结者表达式:数字
class Number :public Expression {
private:
string value_;
public:
Number(string value):value_(value)
{ }
double interpret(unordered_map<string, double> var)
{
return var[value_];
}
};
//终结者表达式:加法
class Add :public Expression {
private:
shared_ptr<Expression> left_;
shared_ptr<Expression> right_;
public:
Add(Expression* left, Expression* right)
: left_(left), right_(right) {
}
double interpret(unordered_map<string, double> var) override {
int leftVal = left_->interpret(var);
int rightVal = right_->interpret(var);
int result = leftVal + rightVal;
cout << "计算: " << leftVal << " + " << rightVal << " = " << result << endl;
return result;
}
};
//终结者表达式:减法
class Subtract :public Expression {
private:
shared_ptr<Expression> left_;
shared_ptr<Expression> right_;
public:
Subtract(Expression* left, Expression* right)
: left_(left), right_(right) {
}
double interpret(unordered_map<string, double> var) override {
int leftVal = left_->interpret(var);
int rightVal = right_->interpret(var);
int result = leftVal - rightVal;
cout << "计算: " << leftVal << " - " << rightVal << " = " << result << endl;
return result;
}
};
//设计解析器封装类,
//栈的核心算法作用:将中缀表达式转换为表达式树,使用栈来管理表达式的构建过程,确保运算顺序的正确性。这个算法中的表达式构建器的扮演角色:管理运算顺序、存储中间表达式。
class Calculator {
public:
Calculator(vector<string> expstr)
{//将字符串序列转换为表达式树
stack<Expression*>stack;//用于临时存储表达式片段
Expression* left;
Expression* right;
for (int i = 0; i < expstr.size(); i++)
{
cout << " 处理 token[" << i << "]: " << expstr[i] << endl;
if (expstr[i] == "+")
{
left = stack.top();
stack.pop();
right =new Number (expstr[++i]);
stack.push(new Add(left, right));
cout << " 创建加法: " << expstr[i - 1] << " + " << expstr[i] << endl;
}
else if (expstr[i] == "-")
{
left = stack.top();
stack.pop();
right = new Number(expstr[++i]);
stack.push(new Subtract(left, right));
cout << " 创建减法: [表达式] - " << expstr[i] << endl;
}
else
{
stack.push(new Number(expstr[i]));
}
}
this->mpression = stack.top();
}
double run(unordered_map<string, double> var)
{
return this->mpression->interpret(var);
}
private:
Expression* mpression;
};
void getexpstr(vector<string>& expstr)
{
cout << "请输入算数表达式" << endl;
string str;
int currentindex = 0;//当前输入字符串中的位置
getline(cin, str);//读取整行输入
string temp;
int len = 0;
for (int i = 0; i < str.size(); i++)
{
switch (str[i])
{
case '+':
len = i - currentindex;
temp = str.substr(currentindex, len);
temp.erase(remove(temp.begin(), temp.end(),' '), temp.end());
currentindex = i + 1;
expstr.push_back(temp);
expstr.push_back("+");
break;
case'-':
len = i - currentindex;
temp = str.substr(currentindex, len);
currentindex = i + 1;
temp.erase(remove(temp.begin(), temp.end(), ' '), temp.end());
expstr.push_back(temp);
expstr.push_back("-");
break;
}
}
//获取最后一个变量
temp = str.substr(currentindex);
temp.erase(remove(temp.begin(), temp.end(), ' '), temp.end());
expstr.push_back(temp);
}
//变量收集器
void getvalue(unordered_map<string, double>& var, vector<string>& expstr)
{
// 🎯 遍历所有token,只处理变量(跳过运算符)
for (auto& key : expstr)
{
if (key != "+" && key != "-")
{
if (var.find(key) ==var.end())
{
//未设置变量的值
cout << "输入key的值:" << key<<endl;
cin >> var[key];//从输入获取值
}
}
}
}
string vector_to_string(vector<string>& expStr)
{
string str;
for (auto& e : expStr)
{
str.append(e);
str.append(" ");
}
str.pop_back();//删除最后一个多余的空格
return str;
}
int main()
{
vector<string> v;
getexpstr(v);//输入表达式
unordered_map<string, double> m;
getvalue(m, v);//输入表达式代表的值
Calculator c(v);//计算带有值的表达式
cout << c.run(m) << endl;//得到结果
return 0;
}
迭代器模式
概念
提供一种方法顺序访问一个聚合对象中的各个元素而不需要暴露该对象的内部表示。
迭代器接口:用于访问元素的头尾以及快速遍历元素的通用操作
具体迭代器实现对象:包含获取元素的头尾,以及是否到结尾的实现,记录当前遍历位置。
聚合对象:定义创建迭代器的方法,提供获取元素数量和访问元素的基本操作。
具体聚合对象:实现聚合接口,存储实际元素,负责创建对应的迭代器实例。
迭代器本质:控制访问聚合对象中的元素
优点:单一职责原则(聚合类负责数据存储,迭代器类专注于遍历逻辑)、开闭原则(可以引入新的迭代器类型)、灵活性、简化客户端代码(使用统一接口遍历不同集合、无需了解集合的内部结构)
缺点:复杂性增加(对于简单集合,迭代器过于复杂,需要额外的类和接口)
代码举例
#include <iostream>
#include<string>
#include<vector>
#include<memory>
using namespace std;
//迭代器接口
class Iterator {
public:
~Iterator() = default;
virtual void first()=0;
virtual void next()=0;
virtual bool isDone()=0;
virtual string currentItem()=0;
};
//聚合对象接口
class Aggregate
{
public:
virtual ~Aggregate() = default;
virtual shared_ptr<Iterator> createIterator() = 0;//创建迭代器接口
virtual size_t size()const = 0;//获取数据的长度
virtual string get(int index)const = 0;//获取指定下标的数据
};
//具体聚合-字符串集合
class StringCollection :public Aggregate {
private:
vector<string> data_;
public:
void add(string s)
{
data_.push_back(s);
}
void popback()
{
data_.pop_back();
}
virtual size_t size()const
{
return data_.size();
}
virtual string get(int index)const
{
if (index >= 0 && index < data_.size())
{
return data_[index];
}
return "";
}
virtual shared_ptr<Iterator> createIterator();//创建迭代器接口
};
//具体迭代器 -正向迭代器
class ForwardIterator :public Iterator {
private:
StringCollection &collection;//数据对象
int currentIndex_;//当前下标
public:
ForwardIterator(StringCollection& sc ):collection(sc),currentIndex_(0){}
void first()
{
currentIndex_ = 0;
}
void next()
{
if (!isDone()) {
currentIndex_++;
}
}
virtual bool isDone()
{
if (currentIndex_ < collection.size())
{
return false;
}
return true;
}
virtual string currentItem()
{
if (!isDone()) {
return collection.get(currentIndex_);
}
return "";
}
};
shared_ptr<Iterator> StringCollection::createIterator()
{
return make_shared<ForwardIterator>(*this);
}
int main()
{
StringCollection s;
s.add("hellow");
s.add("long");
s.add("time");
s.add("no see");
auto it = s.createIterator();
for (it->first(); !(it->isDone()); it->next())
{
cout << it->currentItem() << " ";
}
cout << endl;
}