设计模式23种-C++实现

整体图

创建型模式

单例模式

定义

保证一个类只有一个实例,并提供一个全局访问点来访问这个实例

:::info

  1. 只有⼀个实例:在整个应⽤程序中,只存在该类的⼀个实例对象,⽽不是创建多个相同类型的对象
  2. 全局访问点:为了让其他类能够获取到这个唯⼀实例,该类提供了⼀个全局访问点(通常是⼀个静态⽅法),通过这个⽅法就能获得实例

:::

为什么使用单例模式

:::info

  1. 全局控制:保证只有⼀个实例,这样就可以严格的控制客户怎样访问它以及何时访问它,简单的说就是对唯⼀实例的受控访问
  2. 节省资源:也正是因为只有⼀个实例存在,就避免多次创建了相同的对象,从⽽节省了系统资源,⽽且多个模块还可以通过单例实例共享数据
  3. 懒加载:单例模式可以实现懒加载,只有在需要时才进⾏实例化,这⽆疑会提⾼程序的性能。

:::

设计单例模式的要求

:::info

  1. 私有的构造函数:防⽌外部代码直接创建类的实例
  2. 私有的静态实例变量:保存该类的唯⼀实例
  3. 公有的静态⽅法:通过公有的静态⽅法来获取类的实例

:

#实现

饿汉式

类加载时就已经完成了实例的创建,不管后⾯创建的实例有没有使⽤,先创建再说,所以叫做"饿汉"

多线程环境下

由于饿汉式在程序启动阶段就完成了实例的初始化,因此不存在多个线程同时尝试初始化实例的问题

代码实现

实例在类加载时就被创建, 实现简单,但是实例没有使⽤会造成资源浪费

cpp 复制代码
//class  Singleton{
private:
  static Singleton* instance=new Singleton();
  //私有化构造方法,防止外部实例化
  Singleton(){}

public:
   static Singleton* getInstance(){
       return instance;
   }
};
懒汉式

只有在请求实例时才会创建,如果在⾸次请求时还没有创建,就创建⼀个新的实例,如果已经创建,就返回已有的实例,意思就是需要使⽤了再创建,所以称为"懒汉"

多线程环境下

多个线程同时访问 getInstance() ⽅法,并且在同⼀时刻检测到实例没有被创建,就可能会同时创建实例,从⽽导致多个实例被创建,

可以采⽤同步机制互斥锁来确保在任何时刻只有⼀个线程能够执⾏实例的创建。

:::info

例⼦:你和⼩明都发现家⾥没⽶了,在你们没有相互通知的情况下,都会去超市买⼀袋⽶,这样就重复购买了,违背了单例模式

:::

代码实现

第⼀次使⽤时才创建

cpp 复制代码
//class Singleton{
private:
   //私有化构造方法,防止外部实例化
  Singleton(){}

  static Singleton* instance;
public:
  static Singleton* getinstance{
     if(intance!=NULL){
         
     }
  }
};

什么时候使用单例模式

:::info

  1. 资源共享

多个模块共享某个资源的时候,可以使⽤单例模式,⽐如说应⽤程序需要⼀个全局的配置管理器来存储和管理配置信息、亦或是使⽤单例模式管理数据库连接池

  1. 只有⼀个实例

当系统中某个类只需要⼀个实例来协调⾏为的时候,可以考虑使⽤单例模式, ⽐如说管理应⽤程序中的缓存,确保只有⼀个缓存实例,避免重复的缓存创建和管理,或者使⽤单例模式来创建和管理线程池

  1. 懒加载

如果对象创建本身就⽐较消耗资源,⽽且可能在整个程序中都不⼀定会使⽤,可以使⽤单例模式实现懒加载。在许多流⾏的⼯具和库中,也都使⽤到了单例设计模式

:::

题目:小明的购物车

这段代码的功能是:

  • 维护一个全局唯一的"购物车"对象;
  • 用户输入商品名和数量(例如输入:apple 2banana 3);
  • 程序将商品添加进购物车;
  • 输入结束后,输出所有商品及其数量。
cpp 复制代码
#include <iostream>
#include <unordered_map>
#include <string>
#include <vector>
using namespace std;
 
class ShoppingCartManager {
public:
 
    // 获取购物车实例
    static ShoppingCartManager& getInstance() {
        static ShoppingCartManager instance;
        return instance;
    }
    // 添加商品到购物车
    void addToCart(const string& itemName, int quantity) {
        if(cart.find(itemName)==cart.end()){
            order.emplace_back(itemName);
        }
        cart[itemName] += quantity;
    }
    // 查看购物车
    void viewCart(){
        for (const auto& item : order) {
            cout << item << " " <<cart[item]<< endl;
        }
    }
 
private:
    //商品顺序
    vector<string>order;
    // 私有构造函数
    ShoppingCartManager() {}
    // 购物车存储商品和数量的映射
    unordered_map<string, int> cart;
    
    ShoppingCartManager(const ShoppingCartManager&)=delete;
    ShoppingCartManager& operator=(const ShoppingCartManager&)=delete;
};
 
int main() {
    ShoppingCartManager& cart = ShoppingCartManager::getInstance();
    string itemName;
    int quantity;
    while (cin >> itemName >> quantity) {
        // 获取购物车实例并添加商品
        cart.addToCart(itemName, quantity);
    }
    // 输出购物车内容
    cart.viewCart();
 
    return 0;
}

工厂方法模式

定义

:::info

程序通过不同的"工厂"(CircleFactorySquareFactory)创建不同的"图形对象"(CircleSquare),并调用它们的 draw() 方法来输出形状类型。

输入示例:

:::

plain 复制代码
2
Circle 3
Square 2

输出结果:

plain 复制代码
Circle Block
Circle Block
Circle Block
Square Block
Square Block

意思是:

  • 创建了 3 个圆;
  • 创建了 2 个方形;
  • 每个对象被创建时会自动输出自己的类型。
cpp 复制代码
#include<iostream>
#include<vector>
#include<string>
using namespace std;

class Shape{
public:
virtual void draw()=0;
};

class Circle:public Shape{
public:
void draw() override{
    cout<<"Circle Block"<<endl;
}
};

class Square:public Shape{
public:
void draw() override{
    cout<<"Square Block"<<endl;
}
};

class ShapeFactory{
public:
virtual Shape* createShape()=0;
};

class CircleFactory:public ShapeFactory{
public:
Shape* createShape() override{
    return new Circle();
}
};

class SquareFactory:public ShapeFactory{
public:
Shape* createShape() override{
    return new Square();
}
};

class ShapeFactorySystem{
public:
void produceShapes(ShapeFactory* factory,int quantity){
    for(int i=0;i<quantity;i++){
        Shape* shape=factory->createShape();
        shapes.push_back(shape);
        shape->draw();
    }
}

~ShapeFactorySystem(){
    for(Shape* item:shapes){
        delete item;
    }
}
private:
vector<Shape*>shapes;
};

int main(){
    int N;
    cin>>N;
    ShapeFactorySystem sfs;
    for(int i=0;i<N;i++){
        string Name;
        int num;
        cin>>Name>>num;
        if(Name=="Circle"){
            sfs.produceShapes(new CircleFactory(),num);
        }
        else if(Name=="Square"){
            sfs.produceShapes(new SquareFactory(),num);
        }
    }

    return 0;
}

优点:

  1. 解耦:客户端不依赖具体类,只依赖抽象接口;
  2. 可扩展性强:新增图形时,只需增加一个新类和新工厂;
  3. 遵守开闭原则(OCP):新增功能不需要改原有代码;
  4. 结构清晰:创建逻辑集中在工厂类中,职责单一。

缺点:

  • 每新增一种产品(图形),都要新增一个工厂类;
  • 类的数量可能较多。

抽象工厂模式

这段代码模拟了一个"家具生产系统":

  • 有两种风格:modern(现代风格)classical(古典风格)
  • 每种风格的工厂可以生产 椅子(Chair)沙发(Sofa)
  • 不同风格的工厂生产出的家具样式不同;
  • 程序根据输入的家具类型(modern/classical)动态创建对应工厂,并生产家具

运行流程:

  1. 输入测试次数 N
  2. 每次输入一个风格名称(modern/classical);
  3. 创建对应的工厂;
  4. 工厂负责生产沙发和椅子;
  5. 输出家具信息;
  6. 释放内存。
cpp 复制代码
#include<iostream>
#include<vector>
#include<string>
using namespace std;

class Sofa{
public:
virtual void show()=0;
};

class Chair{
public:
virtual void show()=0;
};

class ModernSofa:public Sofa{
public:
void show() override{
    cout<<"modern sofa"<<endl;
}
};

class ModernChair:public Chair{
public:
void show() override{
    cout<<"modern chair"<<endl;
}
};

class ClassicalChair:public Chair{
public:
void show() override{
    cout<<"classical chair"<<endl;
}
};

class ClassicalSofa:public Sofa{
public:
void show() override{
    cout<<"classical sofa"<<endl;
}
};

class FurnitureFactory{
public:
virtual Sofa* createSofa()=0;
virtual Chair* createChair()=0;
};

class ModernFurnitureFactory:public FurnitureFactory{
public: 
Sofa* createSofa() override{
    return new ModernSofa();
}
Chair* createChair() override{
    return new ModernChair();
}
};

class ClassicalFurnitureFactory:public FurnitureFactory{
public: 
Sofa* createSofa() override{
    return new ClassicalSofa();
}
Chair* createChair() override{
    return new ClassicalChair();
}
};

int main(){
    int N;
    cin>>N;
    string Name;
    for(int i=0;i<N;i++){
        cin>>Name;
        FurnitureFactory* factory=nullptr;
        if(Name=="modern"){
            factory=new ModernFurnitureFactory();
        }
        else if(Name=="classical"){
            factory=new ClassicalFurnitureFactory();
        }
        //根据工厂生成沙发和椅子
        Chair* chair=factory->createChair();
        Sofa* sofa=factory->createSofa();
        chair->show();
        sofa->show();
        delete factory;
        delete chair;
        delete sofa;
    }

    return 0;
}

优点(Advantages)

  1. 产品族的一致性
    • 一个工厂生产的一整套产品(如现代沙发+现代椅子)风格统一;
    • 防止"混搭"出错(不会出现现代沙发 + 古典椅子)。
  2. 解耦创建与使用
    • 客户端只与 FurnitureFactory 交互;
    • 不依赖具体产品类,方便维护和扩展。
  3. 易于扩展新的产品族
    • 想增加新风格(如 VictorianFurnitureFactory),只需添加对应工厂和产品类;
    • 不需要修改旧代码。
  4. 遵循"开闭原则"
    • 对扩展开放,对修改关闭;
    • 新增产品族时无需修改已有逻辑。

缺点(Disadvantages)

  1. 增加产品种类困难
    • 如果要在所有工厂中新增一个新产品(比如"桌子 Table"),
      → 就必须修改所有工厂类(添加 createTable()),破坏开闭原则。
  2. 类数量较多
    • 每个产品族都要有多个产品类 + 一个工厂类;
    • 项目规模大时,类文件可能非常多。

工厂方法和抽象工厂的区别

场景 工厂方法模式 抽象工厂模式
产品种类 只有一种类型的产品(单一维度变化) 多种相关产品(多维度变化)
扩展方式 新增产品类型(新增工厂) 新增产品族(新增整套工厂 + 产品)
客户端创建需求 创建单个对象 创建多个关联对象
示例 图形系统:圆、方形、三角形 UI 主题系统:按钮+输入框+菜单(同风格)

建造者模式

定义

建造者模式(Builder Pattern) 是一种创建型设计模式

用于将复杂对象的构建过程与其表示分离

使得相同的构建过程可以创建不同的表示。

通俗地说,就是:

"让一个指挥者(Director)按照一定的步骤(建造过程)去指导建造者(Builder)组装出复杂的对象(Product)。"

流程(构建过程)

  1. 用户输入要造的车类型(mountainroad)。
  2. 客户端创建相应的建造者对象(MountainBikeBuilderRoadBikeBuilder)。
  3. 客户端把建造者交给指挥者 BikeDirector
  4. 指挥者调用建造者的建造步骤:
plain 复制代码
builder.buildFrame();
builder.buildTires();
  1. 建造者在内部构建 Bike 对象并返回。
  2. 最后打印出结果。

示例

输入:

plain 复制代码
2
mountain
road

输出:

plain 复制代码
Aluminum Frame Knobby Tires
Carbon Frame Slim Tires
cpp 复制代码
#include<iostream>
#include<string>
using namespace std;

class Bike{
  friend ostream& operator<<(ostream&out,const Bike& bike);
public:
   void  setFrame(const string& frame){
       this->frame=frame;
   }
   void setTires(const string& tires){
       this->tires=tires;
   }
private:
   string frame;//车架
   string tires;//轮胎
};

ostream& operator<<(ostream& out,const Bike& bike){
    out<<bike.frame<<" "<<bike.tires;
    return out;
}

class BikeBuilder{
public:
  virtual void buildFrame()=0;
  virtual void buildTires()=0;
  virtual Bike& getResult()=0;
};

class MountainBikeBuilder:public BikeBuilder{
public:
  void buildFrame() override{
     bike.setFrame("Aluminum Frame");
  }
  
  void buildTires() override{
      bike.setTires("Knobby Tires");
  }
  Bike& getResult() override{
      return bike;
  }
private:
  Bike bike;
};

class RoadBikeBuilder:public BikeBuilder{
public:
  void  buildFrame() override{
       bike.setFrame("Carbon Frame");
  }
  
  void buildTires() override{
       bike.setTires("Slim Tires");
  }
  Bike& getResult() override{
      return bike;
  }
private:
  Bike bike;
};

class BikeDirector{
public:
   Bike& construct(BikeBuilder& builder){
       builder.buildFrame();
       builder.buildTires();
       return builder.getResult();
   }
};

int main(){
    int N;
    cin>>N;
    string Name;
    for(int i=0;i<N;i++){
        cin>>Name;
        BikeBuilder *builder;
        if(Name=="mountain"){
            builder=new MountainBikeBuilder();
        }
        else if(Name=="road"){
            builder=new RoadBikeBuilder();
        }
        BikeDirector director;
        Bike bike=director.construct(*builder);
        cout<<bike<<endl;
        delete builder;
    }
    return 0;
}
cpp 复制代码
#include<iostream>
#include<string>
using namespace std;

class Bike{
   friend ostream& operator<<(ostream&out,const Bike* bike);
public:
   void  setFrame(const string& frame){
       this->frame=frame;
   }
   void setTires(const string& tires){
       this->tires=tires;
   }
private:
   string frame;//车架
   string tires;//轮胎
};

ostream& operator<<(ostream& out,const Bike* bike){
    out<<bike->frame<<" "<<bike->tires;
    return out;
}

class BikeBuilder{
public:
  virtual void buildFrame()=0;
  virtual void buildTires()=0;
  virtual Bike* getResult()=0;
  virtual ~BikeBuilder()=default;
};

class MountainBikeBuilder:public BikeBuilder{
public:
  MountainBikeBuilder(){
      bike=new Bike();
  }
  void buildFrame() override{
     bike->setFrame("Aluminum Frame");
  }
  
  void buildTires() override{
      bike->setTires("Knobby Tires");
  }
  Bike* getResult() override{
      return bike;
  }
  ~MountainBikeBuilder(){
      delete bike;
  }
private:
  Bike* bike;
};

class RoadBikeBuilder:public BikeBuilder{
public:
  RoadBikeBuilder(){
    bike=new Bike();
  }
  void  buildFrame() override{
       bike->setFrame("Carbon Frame");
  }
  
  void buildTires() override{
       bike->setTires("Slim Tires");
  }
  Bike* getResult() override{
      return bike;
  }
  ~RoadBikeBuilder(){
    delete bike;
  }
private:
  Bike* bike;
};

class BikeDirector{
public:
   Bike* construct(BikeBuilder* builder){
       builder->buildFrame();
       builder->buildTires();
       return builder->getResult();
   }
};

int main(){
    int N;
    cin>>N;
    string Name;
    for(int i=0;i<N;i++){
        cin>>Name;
        BikeBuilder* builder;
        if(Name=="mountain"){
            builder=new MountainBikeBuilder();
        }
        else if(Name=="road"){
            builder=new RoadBikeBuilder();
        }
        else{
            continue;
        }
        BikeDirector director;
        Bike* bike=director.construct(builder);
        cout<<bike<<endl;
        delete builder;
    }
    return 0;
}

优缺点

优点:

  1. 分离构建过程与表示 ------ 不同建造者可以创建不同表示;
  2. 更易于扩展 ------ 新增一种类型的自行车,只需新建一个 Builder 子类;
  3. 封装性好 ------ 客户端不需要知道产品内部的细节,只需要告诉指挥者"造车"。

缺点:

  • 对于简单对象,使用建造者模式可能显得结构过于复杂。

原型模式

定义

原型模式(Prototype Pattern) 是一种 创建型设计模式

其核心思想是:

"通过复制(克隆)现有的对象来创建新对象,而不是通过实例化类来创建。"

换句话说,当创建一个对象的代价比较高(比如初始化复杂、资源消耗大)时,可以通过复制一个已有对象的副本来得到新的对象

运行流程分析

  1. 用户输入矩形的属性(颜色、宽、高)。
  2. 程序根据输入创建多个原型对象:
plain 复制代码
new RectanglePrototype(Color, Width, Height);
  1. 然后,程序通过调用每个对象的:
plain 复制代码
rectangle->clone();

来克隆(复制)出新的矩形对象。

  1. 每个克隆对象都具有与原对象完全相同的属性。
  2. 最后输出克隆结果,并释放内存。

示例

输入:

plain 复制代码
Red 10 20
3

输出:

plain 复制代码
Color: Red, Width: 10, Height: 20
Color: Red, Width: 10, Height: 20
Color: Red, Width: 10, Height: 20
cpp 复制代码
#include<iostream>
#include<string>
#include<vector>
using namespace std;

class Prototype{
public:
    virtual Prototype* clone()=0;
    virtual string getDetails()=0;
    virtual ~Prototype(){}
};

class RectanglePrototype:public Prototype{
public:
    RectanglePrototype(string color,int width,int height){
        this->color=color;
        this->width=width;
        this->height=height;
    }
    Prototype* clone() override{
        return new RectanglePrototype(*this);
    }
    string getDetails() override{
         return "Color: "+color+", Width: "+
         to_string(width)+", Height: "+to_string(height);
    }
private:
  string color;
  int width;
  int height;
};

int main(){
    string Color;
    int Height,Width;
    cin>>Color>>Width>>Height;
    int N;
    cin>>N;
    vector<Prototype*>rectangles;
    for(int i=0;i<N;i++){
       Prototype* originalRectangle=new RectanglePrototype(Color,Width,Height);
       rectangles.push_back(originalRectangle);
    }
    //克隆对象并输出信息
    for(const auto &rectangle:rectangles){
       Prototype* clonedRectangle=rectangle->clone();
       cout<<clonedRectangle->getDetails()<<endl;
       //释放克隆对象内存
       delete clonedRectangle;
    }
    //释放原型对象内存
    for(const auto &rectangle:rectangles){
        delete rectangle;
    }
    
    return 0;
}

优缺点

优点:

  1. 提高性能
    不需要重新初始化对象,通过复制已有对象创建新对象更快。
  2. 简化对象创建逻辑
    不用依赖复杂的构造函数。
  3. 动态扩展性好
    可以在运行时决定复制哪个对象。

缺点:

  • 若对象内部含有复杂的引用或深层结构,克隆实现可能比较复杂。
  • 需要确保被克隆对象能正确复制(深拷贝与浅拷贝问题)。

结构性设计模式

适配器模式

这段代码模拟了两种不同接口的充电设备:

  • USB接口设备(旧设备)
  • Type-C接口设备(新设备)

现实中我们常遇到这种情况:

比如你的新电脑只有 Type-C 接口,但老的充电器还是 USB 接口,那就需要一个"适配器"来连接它们。

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

//USN接口
class USB{
public:
    virtual void charge()=0;
};

//TypeC接口
class TypeC{
public:
    virtual void chargeWithTypeC()=0;
};

//适配器类
class TypeCAdapter:public USB{
public:
   TypeCAdapter(TypeC* typeC){
       this->typeC=typeC;
   }
   void charge() override{
       typeC->chargeWithTypeC();
   }
private:
  TypeC* typeC;
};

//新电脑类,使用TypeC接口
class NewComputer:public TypeC{
public:
   void chargeWithTypeC() override{
       cout<<"TypeC"<<endl;
   }
};

//适配器 充电器类,使用USB接口
class AdapterCharger:public USB{
public:
   void charge() override{
      cout<<"USB Adapter"<<endl;
   }
};

int main(){
    int N;
    cin>>N;
    for(int i=0;i<N;i++){
        int num;
        cin>>num;
        if(num==1){
           TypeC* newComputer=new NewComputer();
           newComputer->chargeWithTypeC();
           delete newComputer;
        }
        else if(num==2){
            USB* usbAdapter=new AdapterCharger();
            usbAdapter->charge();
            delete usbAdapter;
        }
    }
    return 0;
}

优点

  1. 提高系统兼容性
    新旧接口不兼容时,只需增加一个适配器类,而无需修改原有代码。
  2. 符合开闭原则
    对扩展开放,对修改关闭。
  3. 复用现有代码
    可以让原本不能一起使用的类协同工作

代理模式

这段程序模拟了一个购房系统:

  • 用户(客户端)想通过一个对象(代理)来买房;
  • 代理会根据条件(房子面积)决定是否允许购买;
  • 如果符合条件(面积 > 100),代理会委托真正的购房者执行购买;
  • 如果不符合条件,则直接拒绝。

也就是说:

✅ 代理控制了访问真实对象的权限

设计意义:

代理类在真实对象前加了一层"访问控制",

客户端不需要直接接触真实对象,而是通过代理间接访问。

运行逻辑:

  1. 用户输入购房次数 N
  2. 创建一个代理对象 homep
  3. 每次输入房屋面积 area
  4. 调用代理对象的 requestPurchase()
  5. 代理决定是否允许购买;
  6. 程序结束释放内存。
cpp 复制代码
#include<iostream>
using namespace std;

//抽象主题
class HomePurchase{
public:
   virtual void requestPurchase(int area)=0; 
};

//真实主题
class HomeBuyer:public HomePurchase{
public:
   void requestPurchase(int area) override{
       cout<<"YES"<<endl;
   }
};

//代理
class Proxy:public HomePurchase{
public:
   Proxy(){
    homebuyer=new HomeBuyer();
   }
   void requestPurchase(int area) override{
       if(area>100){
           homebuyer->requestPurchase(area);
       }
       else{
            cout<<"NO"<<endl;
       }
   }
   ~Proxy(){
      delete homebuyer; 
   }
private:
  HomeBuyer*homebuyer;
};

int main(){
    int N;
    cin>>N;
    HomePurchase* homep=new Proxy();
    int area;
    for(int i=0;i<N;i++){
        cin>>area;
        homep->requestPurchase(area);
    }
    delete homep;
    return 0;
}
cpp 复制代码
#include<iostream>
using namespace std;

//抽象主题
class HomePurchase{
public:
   virtual void requestPurchase(int area)=0; 
};

//真实主题
class HomeBuyer:public HomePurchase{
public:
   void requestPurchase(int area) override{
       cout<<"YES"<<endl;
   }
};

//代理
class Proxy:public HomePurchase{
public:
   void requestPurchase(int area) override{
       if(area>100){
           homebuyer.requestPurchase(area);
       }
       else{
            cout<<"NO"<<endl;
       }
   }
private:
  HomeBuyer homebuyer;
};

int main(){
    int N;
    cin>>N;
    HomePurchase* homep=new Proxy();
    int area;
    for(int i=0;i<N;i++){
        cin>>area;
        homep->requestPurchase(area);
    }
    delete homep;
    return 0;
}

装饰模式

定义:

动态地给一个对象添加额外的职责,而不改变其原有的类结构。

举例

这是一段模拟"咖啡制作系统"的 C++ 程序。

它支持:

  • 两种基础咖啡:BlackCoffee(黑咖啡)、Latte(拿铁)
  • 两种配料装饰:Milk(加牛奶)、Sugar(加糖)

通过输入两个数字(num1 num2),程序决定要冲哪种咖啡,并添加哪种装饰。

输入两数

  • 第一个数字 num1 表示咖啡类型:
    • 1 → BlackCoffee
    • 2 → Latte
  • 第二个数字 num2 表示装饰类型:
    • 1 → Milk
    • 2 → Sugar

:::info

示例:

输入:1 1

输出:

Brewing Black Coffee

Adding Milk

:::

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

class Coffee{
public:
  virtual void brew()=0;
  virtual ~Coffee(){}
};

class BlackCoffee:public Coffee{
public:
    void brew() override{
        cout<<"Brewing Black Coffee"<<endl;
    }
};

class Latte:public Coffee{
public:
   void brew() override{
         cout<<"Brewing Latte"<<endl;
   }
};

class Decorator:public Coffee{
public:
  Decorator(Coffee* coffee):coffee(coffee){}
  void brew() override{
      if(coffee){
        coffee->brew();
      }
  }
protected:
 Coffee* coffee;
};

class Milk:public Decorator{
public:
   Milk(Coffee* coffee):Decorator(coffee){}
   void brew() override{
        Decorator::brew();
        cout<<"Adding Milk"<<endl;
   }
};

class Sugar:public Decorator{
public:
   Sugar(Coffee* coffee):Decorator(coffee){}
   void brew() override{
       Decorator::brew();
       cout<<"Adding Sugar"<<endl;
   } 
};

int main(){
    int num1,num2;
    
    while(cin>>num1>>num2){
        Coffee* coffee=nullptr;
        if(num1==1){
            coffee=new BlackCoffee();
        }
        else if(num1==2){
            coffee=new Latte();
        }
        else{
            continue;
        }
        if(num2==1){
            coffee=new Milk(coffee);
        }
        else if(num2==2){
            coffee=new Sugar(coffee);
        }
        else{
            delete coffee;
            continue;
        }
        coffee->brew();
        delete coffee;
    }
    return 0;
}
cpp 复制代码
#include<iostream>
#include<memory>
using namespace std;

class Coffee{
public:
  virtual void brew()=0;
  virtual ~Coffee(){}
};

class BlackCoffee:public Coffee{
public:
    void brew() override{
        cout<<"Brewing Black Coffee"<<endl;
    }
};

class Latte:public Coffee{
public:
   void brew() override{
         cout<<"Brewing Latte"<<endl;
   }
};

class Decorator:public Coffee{
public:
  Decorator(unique_ptr<Coffee>coffee):coffee(move(coffee)){}
  void brew() override{
      if(coffee){
        coffee->brew();
      }
  }
protected:
 unique_ptr<Coffee>coffee;
};

class Milk:public Decorator{
public:
   Milk(unique_ptr<Coffee>coffee):Decorator(move(coffee)){}
   void brew() override{
        Decorator::brew();
        cout<<"Adding Milk"<<endl;
   }
};

class Sugar:public Decorator{
public:
   Sugar(unique_ptr<Coffee>coffee):Decorator(move(coffee)){}
   void brew() override{
       Decorator::brew();
       cout<<"Adding Sugar"<<endl;
   } 
};

int main(){
    int num1,num2;
    
    while(cin>>num1>>num2){
        unique_ptr<Coffee>coffee;
        if(num1==1){
            coffee=make_unique<BlackCoffee>();
        }
        else if(num1==2){
            coffee=make_unique<Latte>();
        }
        else{
            continue;
        }
        if(num2==1){
            coffee=make_unique<Milk>(move(coffee));
        }
        else if(num2==2){
            coffee=make_unique<Sugar>(move(coffee));
        }
        else{
            continue;
        }
        coffee->brew();
    }
    return 0;
}

为什么Coffee* coffee是protected

在装饰器模式中,将被装饰对象 coffee 设置为 protected,是为了:

  • 让子类(具体装饰器)能够访问它,调用原始功能;
  • 同时保护它不被外部用户直接访问或修改;
  • 兼顾 扩展性封装性

外观模式

定义:

外观模式(Facade Pattern)是一种 结构型设计模式

它为复杂的子系统提供一个统一的接口,使得子系统更容易使用。

换句话说:

"外观类"就是一个「总开关」,对外屏蔽系统内部的复杂细节

例子

这段代码模拟了一个「智能家居电源控制系统」,系统中有三种电器:

  • 空调(Air
  • 台灯(DeskLamp
  • 电视(Television

而类 **Facade**(外观类)为用户提供了一个统一的接口,用来方便地控制这些设备。

用户只需通过 Facade 类调用,就能关闭任意一个或所有电器,而不需要直接操作各个电器对象。

假设你家中有很多智能电器(空调、台灯、电视......),

每个设备都有独立的开关。

你可以逐个去关它们(很麻烦),

但如果有一个"总控制面板"可以一键关闭所有设备,那就简单多了。

👉 这个「总控制面板」就是 外观类(Facade)

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

class Air{
public:
  void shutdown(){
    cout<<"Air Conditioner is turned off."<<endl;
  }
};

class DeskLamp{
public:
  void shutdown(){
    cout<<"Desk Lamp is turned off."<<endl;
  }
};

class Television{
public:
  void shutdown(){
    cout<<"Television is turned off."<<endl;
  }
};

class Facade{
public:
  Facade(){
      air=new Air();
      desklamp=new DeskLamp();
      television=new Television();
  }
  
  void operationAir(){
    air->shutdown();
  }
  
  void operationDesklamp(){
    desklamp->shutdown();
  }
  
  void operationTelevision(){
    television->shutdown();
  }
  
  void operationAll(){
    air->shutdown();
    desklamp->shutdown();
    television->shutdown();
    cout << "All devices are off." << endl;
  }
  
  ~Facade(){
      delete air;
      delete desklamp;
      delete television;
  }

private:
  Air *air;
  DeskLamp* desklamp;
  Television* television;
};

int main(){
    int N;
    cin>>N;
    int num;
    Facade* facade=new Facade();
    for(int i=0;i<N;i++){
        cin>>num;
        if(num==1){
          facade->operationAir();
        }
        else if(num==2){
          facade->operationDesklamp();
        }
        else if(num==3){
          facade->operationTelevision();
        }
        else if(num==4){
          facade->operationAll();
        }
        else{
          cout<<"Invalid device code."<<endl;
          continue;
        }
    }
    delete facade;
    return 0;
}
cpp 复制代码
#include<iostream>
using namespace std;

class Air{
public:
  void shutdown(){
    cout<<"Air Conditioner is turned off."<<endl;
  }
};

class DeskLamp{
public:
  void shutdown(){
    cout<<"Desk Lamp is turned off."<<endl;
  }
};

class Television{
public:
  void shutdown(){
    cout<<"Television is turned off."<<endl;
  }
};

class Facade{
public:
  Facade(){
      air=new Air();
      desklamp=new DeskLamp();
      television=new Television();
  }
  
  void turnOffDevice(int deviceCode){
      switch(deviceCode){
        case 1:
           air->shutdown();
           break;
        case 2:
           desklamp->shutdown();
           break;
        case 3:
           television->shutdown();
           break;
        case 4:
           cout<<"All devices are off."<<endl;
           break;
        default:
           cout<<"Invalid device code."<<endl;
           break;
      }
  }
  
  ~Facade(){
      delete air;
      delete desklamp;
      delete television;
  }

private:
  Air *air;
  DeskLamp* desklamp;
  Television* television;
};

int main(){
    int N;
    cin>>N;
    int num;
    Facade* facade=new Facade();
    for(int i=0;i<N;i++){
        cin>>num;
        facade->turnOffDevice(num);
    }
    delete facade;
    return 0;
}
cpp 复制代码
#include<iostream>
using namespace std;

class Air{
public:
  void shutdown(){
    cout<<"Air Conditioner is turned off."<<endl;
  }
};

class DeskLamp{
public:
  void shutdown(){
    cout<<"Desk Lamp is turned off."<<endl;
  }
};

class Television{
public:
  void shutdown(){
    cout<<"Television is turned off."<<endl;
  }
};

class Facade{
public:
  Facade(){}
  
  void turnOffDevice(int deviceCode){
      switch(deviceCode){
        case 1:
           air.shutdown();
           break;
        case 2:
           desklamp.shutdown();
           break;
        case 3:
           television.shutdown();
           break;
        case 4:
           cout<<"All devices are off."<<endl;
           break;
        default:
           cout<<"Invalid device code."<<endl;
           break;
      }
  }

private:
  Air air;
  DeskLamp desklamp;
  Television television;
};

int main(){
    int N;
    cin>>N;
    int num;
    Facade facade;
    for(int i=0;i<N;i++){
        cin>>num;
        facade.turnOffDevice(num);
    }
    return 0;
}

桥接模式

这段程序模拟了一个「遥控器控制不同品牌电视」的系统。

  • 有不同品牌的电视(Sony、TCL),它们支持相同的操作:开机、关机、换频道;
  • 有不同类型的遥控器操作(OnOperation、OffOperation、ChannelOperation);
  • 用户可以自由组合「遥控器操作」与「电视品牌」;
  • 最后由遥控器对象控制电视对象执行操作。

📘 一句话总结:

把"遥控器操作逻辑"与"电视品牌实现"分离,使它们可以独立变化。

------ 这就是桥接模式(Bridge Pattern) 的核心思想

📘 设计意义:

每种品牌的电视机有自己的实现方式,但接口统一,方便遥控器调用

运行逻辑:

  1. 输入测试次数 N
  2. 每次输入一行:
    第一个数字 → 电视品牌(0=Sony,1=TCL)
    第二个数字 → 操作类型(1=换台,2=开机,3=关机);
  3. 根据输入动态创建电视对象和遥控器;
  4. 调用 remotecontrol->performOperation()
  5. 程序执行对应操作
cpp 复制代码
#include<iostream>
#include<sstream>
#include<vector>
#include<string>
using namespace std;

//实现化接口
class TV{
public:
   virtual void on()=0; 
   virtual void off()=0;
   virtual void channel()=0;
};

//具体实现类
class SonyTV:public TV{
public:
    void on() override{
        cout<<"Sony TV is ON"<<endl;
    }
    void off() override{
        cout<<"Sony TV is OFF"<<endl;
    }
    void channel() override{
        cout<<"Switching Sony TV channel"<<endl;
    }
};

class TCLTV:public TV{
public:
    void on() override{
        cout<<"TCL TV is ON"<<endl;
    }
    void off() override{
        cout<<"TCL TV is OFF"<<endl;
    }
    void channel() override{
        cout<<"Switching TCL TV channel"<<endl;
    }
};

//抽象化接口
class RemoteControl{
public:
   RemoteControl(TV* tv):tv(tv){}
   virtual void performOperation()=0;
protected:
   TV* tv;
};

//创建扩充抽象化类
class OnOperation:public RemoteControl{
public:
   OnOperation(TV* tv):RemoteControl(tv){}
   void performOperation() override{
        tv->on(); 
   }
};

class OffOperation:public RemoteControl{
public:
   OffOperation(TV* tv):RemoteControl(tv){}
   void performOperation() override{
        tv->off(); 
   }
};

class ChannelOperation:public RemoteControl{
public:
   ChannelOperation(TV* tv):RemoteControl(tv){}
   void performOperation() override{
        tv->channel(); 
   }
};


int main(){
    int N;
    cin>>N;
    cin.ignore();
    for(int i=0;i<N;i++){
        string input;
        getline(cin,input);
        istringstream iss(input);
        int NameNum,Operation;
        iss>>NameNum>>Operation;
        
        TV* tv;
        if(NameNum==0){
            tv=new SonyTV();
        }
        else{
            tv= new TCLTV();
        }
        
        RemoteControl* remotecontrol;
        if(Operation==2){
          remotecontrol=new OnOperation(tv);
        }
        else if(Operation==3){
          remotecontrol=new OffOperation(tv);
        }
        else{
          remotecontrol=new ChannelOperation(tv);
        }
        remotecontrol->performOperation();
        delete tv;
        delete remotecontrol;
    }
    
    return 0;
}

优点

  1. 抽象与实现分离
    • 遥控器(抽象层)与电视(实现层)互不影响;
    • 可以独立扩展新电视或新操作。
  2. 提高系统可扩展性
    • 新增一个电视品牌 → 只需新增一个 TV 子类;
    • 新增一个遥控功能 → 只需新增一个 RemoteControl 子类。
  3. 遵循开闭原则(OCP)
    • 新增功能不修改原代码,只扩展类。
  4. 组合灵活
    • 不同品牌电视和不同遥控器操作可以任意搭配。

缺点

  1. 增加系统复杂度
    • 类数量增多;
    • 对小型项目来说结构显得过于复杂。
  2. 需要设计经验
    • 必须清楚哪些部分需要"抽象化分离",否则设计反而多余。

组合模式

这段程序模拟了一个 公司组织结构系统

  • 公司包含多个部门(Department);
  • 部门可以继续包含子部门员工(Employee)
  • 整个结构可以像"树"一样展示层级;
  • 程序使用一个统一的接口 Component 来表示"组织节点",
    不论是"部门"还是"员工",都可以一致地处理和显示。

📘 一句话总结:

这段代码用组合模式(Composite Pattern)

把"部门"和"员工"统一看作一种结构节点,从而用统一的方式处理层次结构

📘 说明:

  • 用户先输入公司名;
  • 输入 N 条记录;
  • 每条记录格式:
plain 复制代码
D 部门名
E 员工名
  • 根据类型创建 DepartmentEmployee
  • 添加到公司结构;
  • 最后输出整个公司层次结构
cpp 复制代码
#include<iostream>
#include<string>
#include<sstream>
#include<vector>
using namespace std;

class Component{
public:
  virtual void display(int depth)=0;
};

class Department:public Component{
public:
  Department(const string& name):name(name){}
  
  void add(Component* component){
      children.push_back(component);
  }
  
  void display(int depth) override{
      string indent(depth*2,' ');
      cout<<indent<<name<<endl;
      for(Component* component:children){
          component->display(depth+1);
      }
  }
private:
  string name;
  vector<Component*>children;
};

class Employee:public Component{
public:
   Employee(const string& name):name(name){}
   void display(int depth) override{
      string indent((depth+1)*2,' ');
      cout<<indent<<name<<endl;
   }
private:
   string name;
};

class Company{
public:
  Company(const string&name):name(name),root(new Department(name)){}
  void add(Component* component){
      root->add(component);
  }
  
  void display(){
      cout<<"Company Structure:"<<endl;
      root->display(0);
  }
private:
   string name;
   Department* root;
};

int main(){
    string companyName;
    getline(cin,companyName);
    Company company(companyName);
    int N;
    cin>>N;
    cin.ignore();
    for(int i=0;i<N;i++){
        string type,name;
        cin>>type;
        getline(cin>>ws,name);
        if(type=="D"){
            Department*department=new Department(name);
            company.add(department);
        }
        else if(type=="E"){
            Employee* employee=new Employee(name);
            company.add(employee);
        }
    }
    company.display();
    return 0;
}

优点

  1. 统一管理接口
    • 部门和员工都继承 Component
    • 客户端不用关心节点类型,统一操作。
  2. 树形结构清晰
    • 易于组织复杂的层级关系(公司、目录树、UI控件等)。
  3. 易扩展
    • 新增节点类型(比如"临时部门")只需继承 Component
  4. 符合开闭原则
    • 扩展节点类型不需要修改原有逻辑。

缺点

  1. 设计复杂
    • 对小型系统来说类结构偏重;
    • 需要管理内存(本例中 new 的对象没有 delete)。
  2. 节点行为受限
    • 所有节点必须继承同一接口,有时会包含一些"无用"函数(例如 add() 对叶子无意义)。

享元模式

这段代码模拟了一个"图形绘制系统":

  • 用户输入命令,如:
plain 复制代码
CIRCLE 10 20
CIRCLE 30 40
RECTANGLE 50 60
  • 程序会根据输入绘制不同的图形(圆形、矩形、三角形);
  • 相同类型的图形对象只会创建一次,之后被共享复用;
  • 当相同类型图形再次绘制时,不会重新创建对象,只是复用同一个对象。

📘 一句话总结:

程序通过共享相同的形状对象 ,避免了重复创建,提高了内存利用率。

这就是------享元模式(Flyweight Pattern)


功能:

  • 不断读取用户输入的命令;
  • 每次调用 **processCommand()**
  • 程序动态创建并复用图形对象。
cpp 复制代码
#include<iostream>
#include<unordered_map>
#include<sstream>
#include<string>
using namespace std;

enum ShapeType{
    CIRCLE,
    RECTANGLE,
    TRIANGLE
};

string shapeTypeToString(ShapeType type){
    switch(type){
        case CIRCLE:
           return "CIRCLE";
        case RECTANGLE:
           return "RECTANGLE";
        case TRIANGLE:
           return "TRIANGLE";
        default:
           return "unknown";
    }
}

class Position{
public:
   Position(int x,int y):x(x),y(y){}
   int getX() const{
       return x;
   }
   int getY() const{
       return y;
   }
private:
   int x;
   int y;
};

class Shape{
public:
  virtual void draw(const Position& position)=0;
  virtual ~Shape(){}
};

class ConcreteShape:public Shape{
public:
   ConcreteShape(ShapeType shapetype):shapetype(shapetype),isFirstTime(true){}
   void  draw(const Position& position) override{
       cout<<shapeTypeToString(shapetype)<<(isFirstTime? " drawn" : " shared")
       <<" at ("<<position.getX()<<", "<<position.getY()<<")\n";
   }
   void setFirsttime(bool firstTime){
       isFirstTime=firstTime;
   }
private:
  bool isFirstTime;
  ShapeType shapetype;
};

class ShapeFactory{
public:
  Shape* getShape(ShapeType type){
      if(shapes.find(type)==shapes.end()){
          shapes[type]=new ConcreteShape(type);
      }
      return shapes[type];
  }
  ~ShapeFactory(){
      for(const auto &entry:shapes){
          delete entry.second;
      }
  }
private:
  unordered_map<ShapeType,Shape*>shapes;
};

void processCommand(ShapeFactory& factory,const string& command);

int main(){
    ShapeFactory factory;
    string command;
    while(getline(cin,command)){
        processCommand(factory,command);
    }
    return 0;
}

void processCommand(ShapeFactory& factory,const string& command){
    istringstream iss(command);
    string shapeTypeStr;
    int x,y;
    iss>>shapeTypeStr>>x>>y;
    ShapeType type;
    if(shapeTypeStr=="CIRCLE"){
        type=CIRCLE;
    }
    else if(shapeTypeStr=="RECTANGLE"){
        type=RECTANGLE;
    }
    else if(shapeTypeStr=="TRIANGLE"){
        type=TRIANGLE; 
    }
    else{
        cerr<<"Invalid shape type: "<<shapeTypeStr<<endl;
        return;
    }
    Shape* shape=factory.getShape(type);
    shape->draw(Position(x,y));
    dynamic_cast<ConcreteShape*>(shape)->setFirsttime(false);
}

优点

  1. 节省内存
    • 共享重复对象,减少内存占用;
    • 特别适合大量相似对象的场景(例如:地图游戏、文字渲染)。
  2. 提升性能
    • 避免频繁创建销毁对象;
    • 对象集中管理,缓存复用。
  3. 结构清晰
    • 明确区分内部状态(共享)与外部状态(变化)。

缺点

  1. 逻辑复杂度增加
    • 需要区分内部和外部状态;
    • 工厂和缓存逻辑较繁琐。
  2. 线程安全问题
    • 共享对象可能在多线程环境下被同时访问,需要同步保护。
  3. 不适合状态差异过大的对象
    • 如果大多数对象的状态都不同,共享意义就不大

行为型模式

观察者模式

定义

:::tips

观察者模式(发布-订阅模式)属于⾏为型模式,定义了⼀种⼀对多的依赖关系,让多个观察者对象同时监听⼀个主题对象,当主题对象的状态发⽣变化时,所有依赖于它的观察者都得到通知并被⾃动更新

观察者模式依赖两个模块:

  1. Subject (主题):也就是被观察的对象,它可以维护⼀组观察者,当主题本身发⽣改变时就会通知观察者
  2. Observer (观察者):观察主题的对象,当"被观察"的主题发⽣变化时,观察者就会得到通知并执⾏相应的处理

:::

:::tips

优点:

  1. 观察者模式将主题和观察者之间的关系解耦,主题只需要关注⾃⼰的状态变化,⽽观察者只需要关注在主题状态变化时需要执⾏的操作,两者互不⼲扰
  2. 观察者和主题是相互独⽴的,可以轻松的增加和删除观察者,这样实现的系统更容易扩展和维护

:::

结构

:::tips

  1. 主题Subject : ⼀般会定义成⼀个接⼝,提供⽅法⽤于注册、删除和通知观察者,通常也包含⼀个状态,当状态发⽣改变时,通知所有的观察者
  2. 观察者Observer : 观察者也需要实现⼀个接⼝,包含⼀个更新⽅法,在接收主题通知时执⾏对应的操作。
  3. 具体主题ConcreteSubject : 主题的具体实现, 维护⼀个观察者列表,包含了观察者的注册、删除和通知⽅法
  4. 具体观察者ConcreteObserver : 观察者接⼝的具体实现,每个具体观察者都注册到具体主题中,当主题状态变化并通知到具体观察者,具体观察者进⾏处理

:::

实现

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


// 观察者接口
class Observer {
public:
    virtual void update(const std::string& message) = 0;
};

// 主题接⼝ 
class Subject {
public:
    virtual void registerObserver(Observer* observer) = 0;
    virtual void removeObserver(Observer* observer) = 0;
    virtual void notifyObservers() = 0;
};}



// 具体主题实现
class ConcreteSubject : public Subject {
private:
    std::vector<Observer*> observers;
    std::string state;

public:
    // 注册观察者
    void registerObserver(Observer* observer) override {
        observers.push_back(observer);
    }

    // 移除观察者
    void removeObserver(Observer* observer) override {
        // 在实际应用中可能需要更复杂的逻辑来移除观察者
        observers.erase(std::remove(observers.begin(), observers.end(), observer), 
            observers.end());
    }

    // 通知观察者
    void notifyObservers() override {
        for (Observer* observer : observers) {
            // 观察者根据传递的信息进行处理
            observer->update(state);
        }
    }

    // 更新状态
    void setState(const std::string& newState) {
        state = newState;
        notifyObservers();
    }
};

// 具体观察者实现
class ConcreteObserver : public Observer {
public:
    void update(const std::string& message) override {
        // 在这里实现具体的更新逻辑
        std::cout << "Received message: " << message << std::endl;
    }
};

什么时候使用观察者模式

:::tips

观察者模式特别适⽤于⼀个对象的状态变化会影响到其他对象,并且希望这些对象在状态变化时能够⾃动更新的情况。 ⽐如说在图形⽤户界⾯中,按钮、滑动条等组件的状态变化可能需要通知其他组件更新,这使得观察者模式被⼴泛应⽤于GUI框架,⽐如Java的Swing框架。

此外,观察者模式在前端开发和分布式系统中也有应⽤,⽐较典型的例⼦是前端框架 Vue , 当数据发⽣变化时,视图会⾃动更新。⽽在分布式系统中,观察者模式可以⽤于实现节点之间的消息通知机制,节点的状态变化将通知其他相关节点。

:::

题目:时间观察者

cpp 复制代码
#include <iostream>
#include <vector>
#include <algorithm> 

// 观察者接口
class Observer {
public:
    virtual void update(int hour) = 0;
    virtual ~Observer() = default; // 添加虚析构函数
};

// 主题接口
class Subject {
public:
    virtual void registerObserver(Observer* observer) = 0;
    virtual void removeObserver(Observer* observer) = 0;
    virtual void notifyObservers() = 0;
    virtual ~Subject() = default; // 添加虚析构函数
};

// 具体主题实现
class Clock : public Subject {
private:
    std::vector<Observer*> observers;
    int hour;

public:
    Clock() : hour(0) {}

    void registerObserver(Observer* observer) override {
        observers.push_back(observer);
    }

    void removeObserver(Observer* observer) override {
        auto it = std::find(observers.begin(), observers.end(), observer);
        if (it != observers.end()) {
            observers.erase(it);
        }
    }

    void notifyObservers() override {
        for (Observer* observer : observers) {
            observer->update(hour);
        }
    }

    // 添加获取观察者的函数
    const std::vector<Observer*>& getObservers() const {
        return observers;
    }

    void tick() {
        hour = (hour + 1) % 24; // 模拟时间的推移
        notifyObservers();
    }
};

// 具体观察者实现
class Student : public Observer {
private:
    std::string name;

public:
    Student(const std::string& name) : name(name) {}

    void update(int hour) override {
        std::cout << name << " " << hour << std::endl;
    }
};

int main() {
    // 读取学生数量
    int N;
    std::cin >> N;

    // 创建时钟
    Clock clock;

    // 注册学生观察者
    for (int i = 0; i < N; i++) {
        std::string studentName;
        std::cin >> studentName;
        clock.registerObserver(new Student(studentName));
    }

    // 读取时钟更新次数
    int updates;
    std::cin >> updates;

    // 模拟时钟每隔一个小时更新一次
    for (int i = 0; i < updates; i++) {
        clock.tick();
    }

    // 释放动态分配的观察者对象
    for (Observer* observer : clock.getObservers()) {
        delete observer;
    }

    return 0;
}

策略模式

这段程序模拟了一个「商品打折系统」:

用户每次输入商品价格和打折策略编号,程序根据不同策略计算优惠后的价格。

例如:

plain 复制代码
输入:
3
100 1
180 2
320 2

输出:

plain 复制代码
90
165
280

表示:

  • 第一次选择打 9 折;
  • 第二次选择满减;
  • 第三次选择满减,金额较大减更多。

📘 一句话总结:

这段程序通过 策略模式 把"计算折扣"的算法独立封装起来,使得在不同情况下可以方便地切换策略,而不用修改主程序逻辑。

策略模式(Strategy Pattern)

定义一系列算法,把它们一个个封装起来,使它们可以相互替换。

让算法的变化独立于使用它们的客户。

cpp 复制代码
#include<iostream>
#include<vector>
#include<cmath>
using namespace std;

class Strategy{
public:
virtual int discount(int price)=0;
virtual ~Strategy()=default;
};

class ConcreteStrategy1:public Strategy{
public: 
//打九折
int discount(int price) override{
    return static_cast<int>(round(0.9*price));
}
};

class ConcreteStrategy2:public Strategy{
public:  
//满减优惠
int discount(int price) override{
    for(int i=3;i>=0;i--){
        if(price>=thresshoulds[i]){
            return price-discounts[i];
        }
    }
    return price;
}
private:
int thresshoulds[4]={100,150,200,300};
int discounts[4]={5,15,25,40};
};

class Context{
public:
void SetContext(Strategy* strategy){
    this->strategy=strategy;
}
int ConcreteContext(int M){
    return strategy->discount(M);
}
private:
Strategy* strategy;
};

int main(){
    int N;
    cin>>N;
    cin.ignore();
    int M;
    int choice;
    for(int i=0;i<N;i++){
        cin>>M>>choice;
        Strategy* strategy;
        if(choice==1){
            strategy=new ConcreteStrategy1();
        }
        else if(choice==2){
            strategy=new ConcreteStrategy2();
        }
        else{
            continue;
        }
        Context context;
        context.SetContext(strategy);
        cout<<context.ConcreteContext(M)<<endl;
        delete strategy;
    }

    return 0;
}

优点

  1. 算法独立、可自由切换
    • 新增策略(例如"买一送一")只需添加一个类,不影响其他代码;
    • 不用改主逻辑。
  2. **避免多重 ****if...else**
    • 原本多个条件判断的逻辑,被"多态"替代;
    • 结构更清晰,符合开闭原则(OCP)。
  3. 代码复用性高
    • 公共的接口定义减少重复。

缺点

  1. 类数量增加
    • 每种算法都要定义一个新类;
    • 类过多可能使系统复杂。
  2. 客户端需要了解不同策略
    • 调用者必须知道有哪些策略可选,并手动选择。

命令模式

定义:

命令模式将"请求"封装为一个对象,从而可以使用不同的请求、队列或日志来参数化对象,并支持撤销与重做操作。

例子

这段程序模拟了一个自动点餐机系统

运行流程:

  1. 用户输入 n(点几次单)
  2. 输入每个饮品名称(例如 Coffee, Tea)
  3. 创建一个命令对象(OrderCommand
  4. 把命令交给调用者(OrderMachine
  5. 调用者执行命令 → 命令通知接收者 → 接收者完成制作
    输出:
plain 复制代码
Coffee is ready!
cpp 复制代码
#include<iostream>
#include<string>
using namespace std;


//接口
class Command{
public:
virtual void execute()=0;
virtual ~Command()=default;
};

//接收者类
class DrinkMaker{
public:
void makeDrink(const string& drinkName){
    cout<<drinkName<<" is ready!"<<endl;
}
};

//具体命令类---点餐命令
class OrderCommand:public Command{
public:
OrderCommand(const string& drinkName,DrinkMaker* receiver):m_drinkName(drinkName),m_receiver(receiver){}

void execute() override{
    m_receiver->makeDrink(m_drinkName);
}
private:
string m_drinkName;
DrinkMaker* m_receiver;
};

//调用者类,点餐机
class OrderMachine{
public:
void setCommand(Command* command){
    this->m_command=command;
}

void executeOrder(){
    m_command->execute();
}
private:
Command* m_command;
};

int main(){
    int n;
    cin>>n;
    cin.ignore();
    string Order;
    DrinkMaker drinkmaker;//接收者
    for(int i=0;i<n;i++){
        cin>>Order;
        //命令对象
        Command* command=new OrderCommand(Order,&drinkmaker);
        //执行命令
        OrderMachine ordermachine;
        ordermachine.setCommand(command);
        ordermachine.executeOrder();

        delete command;
    }

    return 0;
}

优点:

  1. 解耦调用者与接收者:调用者不直接操作接收者。
  2. 易于扩展新命令:只需新增命令类,无需改原逻辑。
  3. 支持命令队列、日志、撤销等扩展功能
  4. 符合开闭原则(OCP)

缺点:

  • 类数量增多(每个命令都是一个新类)。
  • 逻辑简单时显得有点"过度设计"。

中介者模式

这是一个 模拟多人聊天室的系统

  • 每个用户(ChatUser)可以向聊天室发送消息;
  • 聊天室(中介者)接收到消息后,会转发给其他所有用户;
  • 每个用户再接收消息并显示。

定义

用一个中介对象来封装一系列对象之间的交互。

使各个对象不需要相互引用,从而实现松耦合,便于修改与扩展

📘 要点:

  • 用户之间 不直接通信
  • 所有消息都通过中介者(聊天室)传递;
  • 新增用户或修改逻辑时,不影响其他类
cpp 复制代码
#include <iostream>
#include <vector>
#include <map>
#include <list>
using namespace std;

// 抽象中介者
class ChatRoomMediator;

// 抽象同事类(用户基类)
class ChatUser {
private:
    string name;                  // 用户名
    ChatRoomMediator* mediator;   // 持有中介者对象指针
    list<string> receivedMessages; // 存储收到的消息

public:
    ChatUser(const string& name, ChatRoomMediator* mediator);

    string getName() const {
        return name;
    }

    // 发送消息
    void sendMessage(const string& message);

    // 接收消息(由子类实现具体行为)
    virtual void receiveMessage(const string& sender, const string& message) = 0;

    list<string> getReceivedMessages() const {
        return receivedMessages;
    }

protected:
    // 添加到接收列表
    void addReceivedMessage(const string& message) {
        receivedMessages.push_back(message);
    }
};

// 具体同事类(普通用户)
class ConcreteChatUser : public ChatUser {
public:
    ConcreteChatUser(const string& name, ChatRoomMediator* mediator);

    void receiveMessage(const string& sender, const string& message) override;
};

// 抽象中介者(聊天室接口)
class ChatRoomMediator {
public:
    virtual void sendMessage(const string& sender, const string& message) = 0;
    virtual void addUser(ChatUser* user) = 0;
    virtual map<string, ChatUser*> getUsers() = 0;
    virtual ~ChatRoomMediator() = default;
};

// 具体中介者(聊天室实现)
class ChatRoomMediatorImpl : public ChatRoomMediator {
private:
    map<string, ChatUser*> users; // 保存所有注册用户

public:
    // 发送消息:通知除发送者外的所有用户
    void sendMessage(const string& sender, const string& message) override {
        for (const auto& userPair : users) {
            if (userPair.first != sender) {
                userPair.second->receiveMessage(sender, message);
            }
        }
    }

    // 注册用户
    void addUser(ChatUser* user) override {
        users[user->getName()] = user;
    }

    map<string, ChatUser*> getUsers() override {
        return users;
    }
};

// 实现 ChatUser 成员函数
ChatUser::ChatUser(const string& name, ChatRoomMediator* mediator)
    : name(name), mediator(mediator) {
    mediator->addUser(this); // 注册到聊天室
}

// ✅ 缺失部分:补全 sendMessage()
void ChatUser::sendMessage(const string& message) {
    cout << name << " sends message: " << message << endl;
    mediator->sendMessage(name, message);
}

// 实现具体用户类
ConcreteChatUser::ConcreteChatUser(const string& name, ChatRoomMediator* mediator)
    : ChatUser(name, mediator) {}

void ConcreteChatUser::receiveMessage(const string& sender, const string& message) {
    string fullMessage = sender + " says: " + message;
    addReceivedMessage(fullMessage);
    cout << getName() << " received -> " << fullMessage << endl;
}

// 主函数测试
int main() {
    ChatRoomMediatorImpl chatRoom;

    ConcreteChatUser user1("Alice", &chatRoom);
    ConcreteChatUser user2("Bob", &chatRoom);
    ConcreteChatUser user3("Charlie", &chatRoom);

    user1.sendMessage("Hello everyone!");
    user2.sendMessage("Hi Alice!");
    user3.sendMessage("Good morning!");

    return 0;
}

优点

  1. 解耦同事对象
    • 各个对象(用户)不再直接引用彼此;
    • 所有通信都经中介统一管理。
  2. 集中控制
    • 中介者掌握全局通信规则;
    • 易于维护、修改、扩展功能(如群聊、私聊)。
  3. 代码更清晰
    • 消息传递逻辑集中管理,避免复杂的多对多关系。

缺点

  1. 中介者可能过于复杂
    • 所有逻辑集中在中介者中,容易成为"上帝类"(God Object)。
  2. 系统扩展时需小心管理中介逻辑
    • 如果聊天室要支持分组、私信等功能,中介逻辑会越来越多

备忘录模式

程序实现了一个整数计数器 Counter,支持四种操作:

  1. Increment → 当前值 +1
  2. Decrement → 当前值 -1
  3. Undo → 撤销上一步操作
  4. Redo → 重做撤销的操作

定义

在不破坏封装性的前提下,捕获一个对象的内部状态,并在需要时恢复它

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

//备忘录
class Memento{
public:
Memento(int val):value(val){}
int getValue() const{
    return value;
}
private:
int value;
};

//发起人
class Counter{
public:
void increment(){
    redoStack=stack<Memento>();
    undoStack.push(Memento(value));
    value++;
}

void decrement(){
    redoStack=stack<Memento>();
    undoStack.push(Memento(value));
    value--;
}

void undo(){
    if(!undoStack.empty()){
        redoStack.push(Memento(value));
        value=undoStack.top().getValue();
        undoStack.pop();
    }
}

void redo(){
    if(!redoStack.empty()){
        undoStack.push(Memento(value));
        value=redoStack.top().getValue();
        redoStack.pop();
    }
}

int getValue() const{
    return value;
}
private:
int value;
stack<Memento>undoStack;
stack<Memento>redoStack;
};

int main(){
    Counter counter;
    string operation;
    while(cin>>operation){
        if(operation=="Increment"){
            counter.increment();
        }
        else if(operation=="Decrement"){
            counter.decrement();
        }
        else if(operation=="Undo"){
            counter.undo();
        }
        else if(operation=="Redo"){
            counter.redo();
        }
        cout<<counter.getValue()<<endl;
    }

    return 0;
}

模板方法

法一

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

class Coffee{
public:
void templateMethod(){
    grind();
    brew();
    add();
}
virtual void grind()=0;
virtual void brew()=0;
virtual void add()=0;
};

class AmericanCoffee:public Coffee{
public:
void grind() override{
    cout<<"Grinding coffee beans"<<endl;
}
void brew() override{
    cout<<"Brewing coffee"<<endl;
}
void add() override{
    cout<<"Adding condiments"<<endl;
}
};

class Latte:public Coffee{
public:
void grind() override{
    cout<<"Grinding coffee beans"<<endl;
}
void brew() override{
    cout<<"Brewing coffee"<<endl;
}
void add() override{
    cout<<"Adding milk"<<endl;
    cout<<"Adding condiments"<<endl;
}
};

int main(){
    int choice;
    while(cin>>choice){
        Coffee* coffee;
        if(choice==1){
            cout<<"Making American Coffee:"<<endl;
            coffee=new AmericanCoffee();
        }
        else if(choice==2){
            cout<<"Making Latte:"<<endl;
            coffee=new Latte();
        }
        coffee->templateMethod();
        delete coffee;
        cout<<endl;
    }

    return 0;
}

法二

cpp 复制代码
#include<iostream>
#include<string>
#include<memory>
using namespace std;

class Coffee{
public:
Coffee(const string& coffeeName):coffeeName(coffeeName){}
virtual void makeCoffee(){
    cout<<"Making "<<coffeeName<<":"<<endl;
    grind();
    brew();
    add();
    cout<<endl;
}

virtual void grind()=0;
virtual void brew()=0;

virtual void add(){
    cout<<"Adding condiments"<<endl;
}
private:
string coffeeName;
};

class AmericanCoffee:public Coffee{
public:
AmericanCoffee():Coffee("American Coffee"){}
void grind() override{
    cout<<"Grinding coffee beans"<<endl;
}
void brew() override{
    cout<<"Brewing coffee"<<endl;
}
};

class Latte:public Coffee{
public:
Latte():Coffee("Latte"){}
void grind() override{
    cout<<"Grinding coffee beans"<<endl;
}
void brew() override{
    cout<<"Brewing coffee"<<endl;
}
void add() override{
    cout<<"Adding milk"<<endl;
    cout<<"Adding condiments"<<endl;
}
};

int main(){
    int choice;
    while(cin>>choice){
        Coffee* coffee;
        if(choice==1){
            coffee=new AmericanCoffee();
        }
        else if(choice==2){
            coffee=new Latte();
        }
        coffee->makeCoffee();
        delete coffee;
    }

    return 0;
}

法三

cpp 复制代码
#include<iostream>
#include<string>
#include<memory>
using namespace std;

class Coffee{
public:
Coffee(const string& coffeeName):coffeeName(coffeeName){}
virtual void makeCoffee(){
    cout<<"Making "<<coffeeName<<":"<<endl;
    grind();
    brew();
    add();
    cout<<endl;
}

virtual void grind()=0;
virtual void brew()=0;

virtual void add(){
    cout<<"Adding condiments"<<endl;
}
private:
string coffeeName;
};

class AmericanCoffee:public Coffee{
public:
AmericanCoffee():Coffee("American Coffee"){}
void grind() override{
    cout<<"Grinding coffee beans"<<endl;
}
void brew() override{
    cout<<"Brewing coffee"<<endl;
}
};

class Latte:public Coffee{
public:
Latte():Coffee("Latte"){}
void grind() override{
    cout<<"Grinding coffee beans"<<endl;
}
void brew() override{
    cout<<"Brewing coffee"<<endl;
}
void add() override{
    cout<<"Adding milk"<<endl;
    cout<<"Adding condiments"<<endl;
}
};

int main(){
    int choice;
    unique_ptr<Coffee>coffeeMaker;
    while(cin>>choice){
        if(choice==1){
            coffeeMaker=make_unique<AmericanCoffee>();
        }
        else if(choice==2){
            coffeeMaker=make_unique<Latte>();
        }
        coffeeMaker->makeCoffee();
    }

    return 0;
}

迭代器模式

程序功能:

  1. 定义了 Student 类,保存学生姓名和学号。
  2. 定义了 StudentCollection 抽象集合类,提供统一接口 begin()end()
  3. ConcreteStudentCollection 实现了具体集合,可以添加学生并返回迭代器。
  4. 主函数:
    • 输入学生数量及信息
    • 添加到集合
    • 使用迭代器遍历集合并输出每个学生信息

📘 总结:

通过迭代器模式,客户端可以统一方式遍历集合,不需要关心集合内部的数据存储结构(例如 vector、list、数组等)

定义

提供一种方法顺序访问一个集合对象中的各个元素,而又 不暴露该对象的内部表

cpp 复制代码
#include<iostream>
#include<vector>
#include<string>
using namespace std;

class Student{
public:
Student(const string& name,const string& studentId):name(name),studentId(studentId){}
string getName() const{
    return name;
}
string getStudentId() const{
    return studentId;
}
private:
string name;
string studentId;
};

class StudentCollection{
public:
virtual ~ StudentCollection()=default;
virtual vector<Student>::iterator begin()=0;
virtual vector<Student>::iterator end()=0;
};

class ConcreteStudentCollection:public StudentCollection{
public:
void addStudents(const Student& student){
    students.push_back(student);
}

vector<Student>::iterator begin() override{
    return students.begin();
}

vector<Student>::iterator end() override{
    return students.end();
}
private:
vector<Student>students;
};

int main(){
    int n;
    cin>>n;
    ConcreteStudentCollection studentcollection;
    for(int i=0;i<n;i++){
        string name,studentId;
        cin>>name>>studentId;
        studentcollection.addStudents(Student(name,studentId));
    }
    for(auto it=studentcollection.begin();it!=studentcollection.end();++it){
        const Student& student=*it;
        cout<<student.getName()<<" "<<student.getStudentId()<<endl;
    }

    return 0;
}
  • 本程序使用了 迭代器模式
  • 核心思想:
  1. 聚合对象提供迭代器接口(begin()end()
  2. 客户端通过迭代器访问集合元素,不关心内部存储结构
  • 优点:
  • 解耦客户端与集合实现
  • 可扩展多种集合类型
  • 遍历逻辑统一

状态模式

程序功能:

  1. 定义三种灯的状态:
    • ON → 灯亮
    • OFF → 灯灭
    • BLINK → 灯闪烁
  2. Light 类持有当前状态对象 State,可以动态切换状态。
  3. 用户输入命令:
    • "ON" → 灯亮
    • "OFF" → 灯灭
    • "BLINK" → 灯闪烁
  4. 输出当前灯的状态。

定义

状态模式(State Pattern)

允许对象在内部状态改变时改变它的行为,对象看起来像改变了类。

核心思想:

  • 将不同状态的行为封装到不同类中
  • 通过环境类维护当前状态
  • 客户端操作环境类,状态类决定行为
cpp 复制代码
#include<iostream>
#include<string>
#include<vector>
using namespace std;

class State{
public:
virtual string handle()=0;
};

class OnState:public State{
public:
string handle() override{
    return "Light is ON";
}
};

class OffState:public State{
public:
string handle() override{
    return "Light is OFF";
}
};

class BlinkState:public State{
public:
string handle() override{
    return "Light is Blinking";
}
};

class Light{
public:
Light():state(new OffState()){}
void setState(State* newstate){
    delete state;
    state=newstate;
}
string performOperation(){
    return state->handle();
}
~Light(){
    delete state;
}
private:
State* state;
};

int main(){
    int n;
    cin>>n;
    cin.ignore();
    Light light;
    for(int i=0;i<n;i++){
        string command;
        getline(cin,command);
        if(command=="ON"){
            light.setState(new OnState());
        }
        else if(command=="OFF"){
            light.setState(new OffState());
        }
        else if(command=="BLINK"){
            light.setState(new BlinkState());
        }
        else{
            continue; 
        }
        cout<<light.performOperation()<<endl;
    }

    return 0;
}
  • 这段代码使用了 状态模式
  • 核心思想:
  1. 状态封装:每种状态行为独立
  2. 环境类持有状态:根据状态调用不同方法
  3. 动态切换状态:客户端无需关心状态内部细节
  • 优点:
  • 行为随状态改变而改变
  • 易于扩展新状态
  • 避免复杂条件判断

责任链模式

程序功能:

  1. 员工提交请假请求(姓名 + 请假天数)。
  2. 请假审批有三个层级:
    • Supervisor(主管):最多批准 3 天
    • Manager(经理):最多批准 7 天
    • Director(总监):最多批准 10 天
  3. 超过审批权限时,自动传递给下一级审批人。
  4. 输出审批结果,例如:
plain 复制代码
Alice 2 → Approved by Supervisor
Bob 5 → Approved by Manager
Charlie 9 → Approved by Director
Dave 12 → Denied by Director

定义

责任链模式

为请求创建一个接收者对象的链。请求沿着链传递,直到有对象处理它。

使发送者和接收者解耦。

cpp 复制代码
#include<iostream>
#include<string>
#include<vector>
#include<sstream>
using namespace std;

class LeaveRequest{
public:
LeaveRequest(const string& name,int days):name(name),days(days){}
string getName() const{
    return name;
}  
int getDays() const{
    return days;
}
private:
string name;
int days;
};

class LeaveHandle{
public:
virtual void handleRequest(LeaveRequest* request)=0;
};

class Supervisor:public LeaveHandle{
public:
Supervisor(LeaveHandle* nextHandler):nextHandler(nextHandler){}

void handleRequest(LeaveRequest* request) override{
    if(request->getDays()<=MAX_DAYS_SUPERVISOR_CAN_APPROVE){
        cout<<request->getName()<<" Approved by Supervisor."<<endl;
    }
    else if(nextHandler!=nullptr){
        nextHandler->handleRequest(request);
    }
    else{
        cout<<request->getName()<<" Denied by upervisor."<<endl;
    }
}
private:
static const int MAX_DAYS_SUPERVISOR_CAN_APPROVE=3;
LeaveHandle* nextHandler;
};

class Manager:public LeaveHandle{
public:
Manager(LeaveHandle* nextHandler):nextHandler(nextHandler){}

void handleRequest(LeaveRequest* request) override{
    if(request->getDays()<=MAX_DAYS_MANAGER_CAN_APPROVE){
        cout<<request->getName()<<" Approved by Manager."<<endl;
    }
    else if(nextHandler!=nullptr){
        nextHandler->handleRequest(request);
    }
    else{
        cout<<request->getName()<<" Denied by Manager."<<endl;
    }
}
private:
static const int MAX_DAYS_MANAGER_CAN_APPROVE=7;
LeaveHandle* nextHandler;
};

class Director:public LeaveHandle{
public:void handleRequest(LeaveRequest* request) override{
    if(request->getDays()<=MAX_DAYS_DIRECTOR_CAN_APPROVE){
        cout<<request->getName()<<" Approved by Director."<<endl;
    }
    else{
        cout<<request->getName()<<" Denied by Director."<<endl;
    }
}
private:
static const int MAX_DAYS_DIRECTOR_CAN_APPROVE=10;
};

int main(){
    int N;
    cin>>N;
    cin.ignore();
    LeaveHandle* director=new Director();
    LeaveHandle* manager=new Manager(director);
    LeaveHandle* supervisor=new Supervisor(manager);
    for(int i=0;i<N;i++){
        string input;
        getline(cin,input);
        istringstream iss(input);
        string name;
        int days;
        if(iss>>name>>days){
            LeaveRequest request(name,days);
            supervisor->handleRequest(&request);
        }
        else{
            cout<<"Invalid input"<<endl;
            return -1;
        }
    }
    delete supervisor;
    delete manager;
    delete director;

    return 0;
}

解释器模式

程序功能:

  1. 支持解析和计算后缀表达式(Reverse Polish Notation, RPN),例如:
plain 复制代码
3 4 + 2 *

表示 (3 + 4) * 2

  1. 支持两种操作:
    • + → 加法
    • * → 乘法
  2. 使用解释器模式,将表达式封装成对象进行计算

定义

解释器模式

为语言中的每个语法规则建立一个类,使用这些类解释或执行特定语言的语句。

cpp 复制代码
#include<iostream>
#include<sstream>
#include<stack>
#include<vector>
#include<regex>
#include<iterator>
#include<stdexcept>
#include<string>
using namespace std;

class Expression{
public:
virtual int interpret()=0;
virtual ~Expression()=default;
};

class NumberExpression:public Expression{
public:
NumberExpression(int val):value(val){}

int interpret() override{
    return value;
}
private:
int value;
};

class AddExpresion:public Expression{
public:
AddExpresion(Expression* l,Expression* r):left(l),right(r){}
int interpret() override{
    return left->interpret()+right->interpret();
}
private:
Expression* left;
Expression* right;
};

class MultiplyExpresion:public Expression{
public:
MultiplyExpresion(Expression* l,Expression* r):left(l),right(r){}
int interpret() override{
    return left->interpret()*right->interpret();
}private:
Expression* left;
Expression* right;
};

class OperatorExpression:public Expression{
public:
OperatorExpression(const string& op):oper(op){}
int interpret() override{
    throw runtime_error("OperatorExpression does not support interpretation");
}

string getOperator(){
    return oper;
}
private:
string oper;
};

int parseExpression(const string& expressionStr){
    istringstream iss(expressionStr);
    vector<string>elements(istream_iterator<string>{iss},istream_iterator<string>());
    stack<Expression*>stack;
    for(const auto& element:elements){
        if(regex_match(element,regex("\\d+"))){
            stack.push(new NumberExpression(stoi(element)));
        }
        else if(element=="+"||element=="*"){
            stack.push(new OperatorExpression(element)); }
        else{
            throw invalid_argument("Invalid element in Exprssion:"+element);
        }
    }
    while(stack.size()>1){
        Expression*right=stack.top();
        stack.pop();
        Expression* operatorExp=stack.top();
        stack.pop();
        Expression*left=stack.top();
        stack.pop();
        if(auto*opExp=dynamic_cast<OperatorExpression*>(operatorExp)){
            string op=opExp->getOperator();
            if(op=="+"){
                stack.push(new AddExpresion(left,right));
            }
            else if(op=="*"){
                stack.push(new MultiplyExpresion(left,right));
            }
        }
        else{
            throw invalid_argument("Invalid operator type in expression");
        }
    }
    int result=stack.top()->interpret();
    delete stack.top();
    return result;
}

int main(){
    vector<string>input_lines;
    string line;
    while(getline(cin,line)&&!line.empty()){
        input_lines.push_back(line);
    }
    for(size_t i=0;i<input_lines.size();++i){
        try{
            int result=parseExpression(input_lines[i]);
            cout<<result<<endl;
        }
        catch(const exception& e){
            cout<<"Error - "<<e.what()<<endl;
        }
    }
    return 0;
}
  • 本程序使用了 解释器模式
  • 核心思想:
  1. 每个数字或操作符封装成对象
  2. 通过组合对象形成 语法树
  3. 调用 interpret() 方法执行表达式
  • 优点:
  • 语法清晰,可扩展
  • 客户端无需关心内部计算逻辑
  • 易于增加新的表达式类型(例如减法、除法、括号)

访问者模式

程序功能:

  1. 定义两种图形:
    • Circle(圆):存储半径
    • Rectangle(矩形):存储宽和高
  2. 定义访问者 Visitor,可对不同图形执行操作(这里是计算面积)
  3. Drawing 类管理图形集合,并允许访问者访问
  4. 用户输入图形类型和参数,程序输出每个图形的面积

示例输入:

plain 复制代码
2
Circle 3
Rectangle 4 5

输出:

plain 复制代码
28.26
20

定义

将作用于某对象结构中的操作封装到访问者对象中,使得可以在不改变对象结构的情况下增加新的操作。

核心思想:

  • 元素类 (Shape)提供 accept() 方法
  • 访问者类(Visitor)封装操作逻辑
  • 具体访问者实现操作(如计算面积、绘制等)
cpp 复制代码
#include<iostream>
#include<cmath>
#include<string>
#include<vector>
using namespace std;

class Shape;

class Visitor{
public:
virtual void visit(class Circle& circle)=0;
virtual void visit(class Rectangle& rectangle)=0;
};

class Shape{
public:
virtual ~Shape(){}
virtual void accept(Visitor& visitor)=0;
};

class Circle:public Shape{
public:
Circle(int radius):radius(radius){}

int getRadius() const{
    return radius;
}

void accept(Visitor& visitor) override;
private:
int radius;
};

class Rectangle:public Shape{
public:
Rectangle(int width,int height):width(width),height(height){}
int getHeight() const{
    return height;
}
int getWidth() const{
    return width;
}
void accept(Visitor& visitor) override;
private:
int width;
int height;
};

class AreaCalculator:public Visitor{
public:
void visit(Circle& circle) override;
void visit(Rectangle& rectangle) override;
};

class Drawing{
public: 
Drawing(const vector<Shape*>& shapes):shapes(shapes){}
void accept(Visitor& visitor){
    for(Shape* shape:shapes){
        shape->accept(visitor);
    }
}
private:
vector<Shape*>shapes;
};

void Circle::accept(Visitor& visitor){
    visitor.visit(*this);
}

void Rectangle::accept(Visitor& visitor){
    visitor.visit(*this);
}

void  AreaCalculator::visit(Circle& circle){
    double area=3.14*pow(circle.getRadius(),2);
    cout<<area<<endl;
}

void  AreaCalculator::visit(Rectangle& rectangle){
    int area=rectangle.getWidth()*rectangle.getHeight();
    cout<<area<<endl;
}

int main(){
    int n;
    cin>>n;
    vector<Shape*>shapes;
    for(int i=0;i<n;i++){
        string type;
        cin>>type;
        if(type=="Circle"){
            int radius;
            cin>>radius;
            shapes.push_back(new Circle(radius));
        }
        else if(type=="Rectangle"){
            int width,height;
            cin>>width>>height;
            shapes.push_back(new Rectangle(width,height));
        }
        else{
            cout<<"Invalid input"<<endl;
            return -1;
        }
    }
    Drawing drawing(shapes);
    AreaCalculator areaCalculator;
    drawing.accept(areaCalculator);
    for(Shape* shape:shapes){
        delete shape;
    }

    return 0;
}
  • 本程序使用了 访问者模式
  • 核心思想:
    1. 元素类只提供 accept() 方法
    2. 具体访问者实现操作(计算面积)
    3. 新操作无需修改元素类,只需新增访问者
  • 优点:
    • 易扩展操作
    • 解耦元素类与操作逻辑
    • 适合对对象结构中元素做多种操作

类模式(Class Patterns)

特点:通过 继承 来实现模式的变化。

  • 依赖于 子类化(subclassing) 来扩展功能
  • 对象在 编译时确定类型
  • 一般耦合度比对象模式高一些

对象模式(Object Patterns)

特点:通过 组合/聚合 来实现模式的变化。

  • 依赖 对象间的引用/委托
  • 对象在 运行时可以动态改变行为
  • 更灵活、耦合度低

状态和策略可以通过类模式也可以通过对象模式实现,推荐对象。

💡 总结记忆法

  • 类模式 = 继承 → 编译时固定,耦合高
  • 对象模式 = 组合 → 运行时可变,耦合低

并发设计模式-补充

生产者消费者模式

1. 概念

生产者-消费者模式 是一种 解耦生成任务和处理任务 的并发设计模式。它的核心思想是:

  • 生产者(Producer):负责产生数据或任务,把它们放入一个共享的缓冲区(通常是队列)。
  • 消费者(Consumer):负责从缓冲区中取出数据或任务进行处理。
  • 缓冲区(Buffer/Queue):生产者和消费者之间的中间存储,用于异步处理。

通过这种方式,生产者和消费者不必直接调用对方,双方通过缓冲区间接通信。


2. 结构图示

plain 复制代码
[生产者] ---> (队列/缓冲区) ---> [消费者]
      ↑                      ↓
      |---- 可并行异步处理 ----|
  • 生产者将任务放入队列。
  • 消费者从队列取任务并处理。
  • 队列可以是 有限队列 (有限缓冲区)或 无限队列(无界缓冲区)。

3. 优点

  1. 解耦:生产者和消费者可以独立运行,互不影响。
  2. 缓冲能力:避免生产过快或消费过慢导致系统阻塞。
  3. 可扩展性:可以增加多个生产者或消费者来扩展系统吞吐量。
  4. 并发控制:通过队列实现线程安全,简化了并发编程的复杂性。

4. 实现方式

cpp 复制代码
#include <iostream>
#include <thread>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <chrono>
#include <random>

std::queue<int> buffer;               // 共享缓冲区
const unsigned int MAX_BUFFER_SIZE = 5;

std::mutex mtx;                        // 互斥锁
std::condition_variable cv_produce;    // 生产者条件变量
std::condition_variable cv_consume;    // 消费者条件变量

// 随机延迟函数
void random_sleep() {
    std::this_thread::sleep_for(std::chrono::milliseconds(rand() % 1000));
}

void producer(int id, int produce_count) {
    for (int i = 0; i < produce_count; ++i) {
        std::unique_lock<std::mutex> lock(mtx);

        cv_produce.wait(lock, [] { return buffer.size() < MAX_BUFFER_SIZE; });

        int item = i + id * 100;  // 生产数据
        buffer.push(item);
        std::cout << "生产者 " << id << " 生产了: " << item << std::endl;

        lock.unlock();
        cv_consume.notify_one();  // 通知消费者
        random_sleep();
    }
}

void consumer(int id, int consume_count) {
    for (int i = 0; i < consume_count; ++i) {
        std::unique_lock<std::mutex> lock(mtx);

        cv_consume.wait(lock, [] { return !buffer.empty(); });

        int item = buffer.front();
        buffer.pop();
        std::cout << "消费者 " << id << " 消费了: " << item << std::endl;

        lock.unlock();
        cv_produce.notify_one();  // 通知生产者
        random_sleep();
    }
}

int main() {
    srand(time(0));

    const int PRODUCER_COUNT = 2;
    const int CONSUMER_COUNT = 2;
    const int ITEM_PER_PRODUCER = 10;

    std::thread producers[PRODUCER_COUNT];
    std::thread consumers[CONSUMER_COUNT];

    // 启动生产者线程
    for (int i = 0; i < PRODUCER_COUNT; ++i) {
        producers[i] = std::thread(producer, i + 1, ITEM_PER_PRODUCER);
    }

    // 启动消费者线程
    for (int i = 0; i < CONSUMER_COUNT; ++i) {
        consumers[i] = std::thread(consumer, i + 1, ITEM_PER_PRODUCER);
    }

    // 等待线程完成
    for (int i = 0; i < PRODUCER_COUNT; ++i) {
        producers[i].join();
    }
    for (int i = 0; i < CONSUMER_COUNT; ++i) {
        consumers[i].join();
    }

    std::cout << "所有生产和消费完成!" << std::endl;

    return 0;
}
相关推荐
spencer_tseng3 小时前
JDK 9 List.of(...)
java·windows·list·1024程序员节
练习时长一年4 小时前
jdk动态代理实现
java·开发语言
闻缺陷则喜何志丹4 小时前
【排序】P9127 [USACO23FEB] Equal Sum Subarrays G|普及+
c++·算法·排序·洛谷
moringlightyn4 小时前
c++ 智能指针
开发语言·c++·笔记·c++11·指针·智能指针
Code_Shark4 小时前
AtCoder Beginner Contest 424 题解
数据结构·c++·算法·数学建模·青少年编程
今天又在学代码写BUG口牙4 小时前
MFC应用程序,工作线程学习记录
c++·mfc·1024程序员节
j_xxx404_4 小时前
C++ STL简介:从原理到入门使用指南
开发语言·c++
忘忧记4 小时前
Excel拆分和合并优化版本
windows·microsoft·excel
15Moonlight4 小时前
06-MySQL基础查询
数据库·c++·mysql·1024程序员节