设计模式学习(3)-行为型模式

文章目录

命令模式(Command Pattern)

它将一个请求封装成一个对象,从而使你可以用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。可以单独执行每一个命令,也可以将命令封装成一个命令宏从而批量执行命令。

UML类图

  • LightOnCommandLightOffCommandFanOnCommandFanOffCommandCommand继承关系 ,使用的是空心三角箭头(空心箭头),箭头从子类指向父类。
  • LightOnCommandLightOffCommandLight依赖关系 ,使用的是虚线箭头,箭头指向被依赖对象。
  • FanOnCommandFanOffCommandFan依赖关系 ,使用的是虚线箭头,箭头指向被依赖对象。
  • MacroCommandCommand继承关系 ,使用的是空心三角箭头(空心箭头) ,箭头从子类指向父类。同时,MacroCommand各Command子类组合关系 ,使用的是实心菱形箭头实线,箭头指向被组合对象。
  • RemoteControl各Command子类组合关系 ,使用的是实心菱形箭头实线,箭头指向被组合对象。

代码示例

cpp 复制代码
#include <iostream>
#include <vector>
#include <stack>
#include <memory>

// 命令接口
class Command {
public:
    virtual ~Command() = default;
    virtual void execute() = 0;
    virtual void undo() = 0; // 支持撤销操作
};

// 接收者1:灯
class Light {
    std::string location_;
    bool isOn_ = false;
public:
    explicit Light(const std::string& location) : location_(location) {}

    void on() {
        isOn_ = true;
        std::cout << location_ << "的灯打开了" << std::endl;
    }
    void off() {
        isOn_ = false;
        std::cout << location_ << "的灯关闭了" << std::endl;
    }
};

// 接收者2:风扇
class Fan {
    std::string location_;
    enum Speed { Off, Low, Medium, High };
    Speed speed_ = Off;
public:
    explicit Fan(const std::string& location) : location_(location) {}

    void on() {
        speed_ = Low;
        std::cout << location_ << "的风扇启动(低速)" << std::endl;
    }

    void off() {
        speed_ = Off;
        std::cout << location_ << "的风扇关闭" << std::endl;
    }

    void setSpeed(Speed speed) {
        speed_ = speed;
        static const char* speedNames[] = {"关闭", "低速", "中速", "高速"};
        std::cout << location_ << "的风扇速度设置为" << speedNames[speed_] << std::endl;
    }

    Speed getSpeed() const { return speed_; }
};

// 具体命令:打开灯
class LightOnCommand : public Command {
private:
    Light* light_;
public:
    explicit LightOnCommand(Light* light) : light_(light) {}
    void execute() override {
        light_->on();
    }
    void undo() override {
        light_->off();
    }
};

// 具体命令:关闭灯
class LightOffCommand : public Command {
private:
    Light* light_;
public:
    explicit LightOffCommand(Light* light) : light_(light) {}
    void execute() override {
        light_->off();
    }
    void undo() override {
        light_->on();
    }
};

// 具体命令:开启风扇低速
class FanOnCommand : public Command {
private:
    Fan* fan_;
    Fan::Speed prevSpeed_;
public:
    explicit FanOnCommand(Fan* fan) : fan_(fan), prevSpeed_(Fan::Off) {}

    void execute() override {
        prevSpeed_ = fan_->getSpeed();
        fan_->on();
    }
    void undo() override {
        fan_->setSpeed(prevSpeed_);
    }
};

// 具体命令:关闭风扇
class FanOffCommand : public Command {
private:
    Fan* fan_;
    Fan::Speed prevSpeed_;
public:
    explicit FanOffCommand(Fan* fan) : fan_(fan), prevSpeed_(Fan::Off) {}

    void execute() override {
        prevSpeed_ = fan_->getSpeed();
        fan_->off();
    }
    void undo() override {
        fan_->setSpeed(prevSpeed_);
    }
};

// 宏命令,执行一组命令
class MacroCommand : public Command {
private:
    std::vector<std::shared_ptr<Command>> commands_;
public:
    void add(const std::shared_ptr<Command>& command) {
        commands_.push_back(command);
    }

    void execute() override {
        for (auto& cmd : commands_) {
            cmd->execute();
        }
    }

    void undo() override {
        // 逆序撤销
        for (auto it = commands_.rbegin(); it != commands_.rend(); ++it) {
            (*it)->undo();
        }
    }
};

// 调用者 - 遥控器
class RemoteControl {
private:
    std::stack<std::shared_ptr<Command>> history_; // 支持撤销的命令历史栈
public:
    void submitCommand(const std::shared_ptr<Command>& cmd) {
        cmd->execute();
        history_.push(cmd);
    }

    void undo() {
        if (!history_.empty()) {
            auto cmd = history_.top();
            cmd->undo();
            history_.pop();
        } else {
            std::cout << "没有命令可以撤销" << std::endl;
        }
    }
};

int main() {
    Light livingRoomLight("客厅");
    Fan ceilingFan("客厅");

    RemoteControl remote;

    // 创建灯的打开关闭命令
    auto lightOn = std::make_shared<LightOnCommand>(&livingRoomLight);
    auto lightOff = std::make_shared<LightOffCommand>(&livingRoomLight);

    // 创建风扇的开、关命令
    auto fanOn = std::make_shared<FanOnCommand>(&ceilingFan);
    auto fanOff = std::make_shared<FanOffCommand>(&ceilingFan);

    // 单独打开灯
    remote.submitCommand(lightOn);

    // 单独关闭灯
    remote.submitCommand(lightOff);

    // 打开风扇
    remote.submitCommand(fanOn);

    // 撤销风扇开启
    remote.undo();

    // 创建宏命令,打开灯和风扇
    auto partyOn = std::make_shared<MacroCommand>();
    partyOn->add(lightOn);
    partyOn->add(fanOn);

    // 创建宏命令,关闭灯和风扇
    auto partyOff = std::make_shared<MacroCommand>();
    partyOff->add(lightOff);
    partyOff->add(fanOff);

    // 执行宏命令
    std::cout << "\n开启派对模式:" << std::endl;
    remote.submitCommand(partyOn);

    // 撤销宏命令
    std::cout << "\n撤销派对模式:" << std::endl;
    remote.undo();

    // 关闭派对模式
    std::cout << "\n关闭派对模式:" << std::endl;
    remote.submitCommand(partyOff);

    return 0;
}
  • 这里的RemoteControlMacroCommand并不是必须的引入的目的主要是做管理和回滚命令。
  • MacroCommand属于将多个Command组合成一系列动作,因此,它既继承了Command又依赖Command子类运行。

中介者模式(Mediator Pattern)

它通过引入一个中介者对象来封装一组对象之间的交互,使各个对象不需要显式地相互引用,从而降低对象之间的耦合度,提高系统的灵活性和可维护性。例如:有一个聊天室系统,多个用户发送消息,不直接发送给彼此,而是通过聊天室(中介者)转发消息。

UML类图

  • ChatMediatorChatRoom继承关系 ,使用的是空心三角箭头(空心箭头),箭头从子类指向父类。
  • UserConcreteUser继承关系 ,使用的是空心三角箭头(空心箭头),箭头从子类指向父类。
  • ConcreteUserChatRoom依赖关系 ,使用的是虚线箭头,箭头指向被依赖对象。

代码示例

cpp 复制代码
#include <iostream>
#include <string>
#include <vector>
#include <memory>

// 抽象中介者
class ChatMediator {
public:
    virtual void sendMessage(const std::string& msg, int userId) = 0;
    virtual void addUser(int userId) = 0;
    virtual ~ChatMediator() = default;
};

// 具体中介者
class ChatRoom : public ChatMediator {
private:
    std::vector<int> users; // 简化用户存储,只存用户ID
public:
    void sendMessage(const std::string& msg, int userId) override {
        for (int id : users) {
            if (id != userId) {
                std::cout << "User" << id << " received: " << msg << std::endl;
            }
        }
    }
    void addUser(int userId) override {
        users.push_back(userId);
    }
};

// 抽象同事类
class User {
protected:
    ChatMediator& mediator;
    int id;
public:
    User(ChatMediator& m, int uid) : mediator(m), id(uid) {
        mediator.addUser(id);
    }
    virtual void send(const std::string& msg) = 0;
    virtual void receive(const std::string& msg) {
        std::cout << "User" << id << " received: " << msg << std::endl;
    }
    virtual ~User() = default;
};

// 具体同事类
class ConcreteUser : public User {
public:
    ConcreteUser(ChatMediator& m, int uid) : User(m, uid) {}
    void send(const std::string& msg) override {
        std::cout << "User" << id << " sends: " << msg << std::endl;
        mediator.sendMessage(msg, id);
    }
};

int main() {
    ChatRoom chatroom;

    ConcreteUser user1(chatroom, 1);
    ConcreteUser user2(chatroom, 2);
    ConcreteUser user3(chatroom, 3);

    user1.send("Hello, everyone!");
    user2.send("Hi User1!");
    user3.send("Good morning!");

    return 0;
}

观察者模式(Observer Pattern)

是一种常用的软件设计模式,它定义了一种一对多的依赖关系,使得当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。

UML类图

  • CurrentConditionsDisplayStatisticsDisplayObserver继承关系 ,使用的是空心三角箭头(空心箭头),箭头从子类指向父类。
  • WeatherDataSubject继承关系 ,使用的是空心三角箭头(空心箭头),箭头从子类指向父类。
  • Subject子类各Observer子类依赖关系 ,使用的是虚线箭头,箭头指向被依赖对象。

代码示例

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

// 抽象观察者
class Observer {
public:
    virtual ~Observer() = default;
    virtual void update(float temperature, float humidity) = 0;
};

// 抽象主题
class Subject {
public:
    virtual ~Subject() = default;
    virtual void registerObserver(Observer* observer) = 0;
    virtual void removeObserver(Observer* observer) = 0;
    virtual void notifyObservers() = 0;
};

// 具体主题------天气数据
class WeatherData : public Subject {
private:
    std::vector<Observer*> observers;
    float temperature;
    float humidity;

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(temperature, humidity);
        }
    }

    // 当天气数据更新时调用此方法
    void setMeasurements(float temp, float hum) {
        temperature = temp;
        humidity = hum;
        notifyObservers();
    }
};

// 具体观察者------显示设备1
class CurrentConditionsDisplay : public Observer {
private:
    float temperature;
    float humidity;

public:
    void update(float temp, float hum) override {
        temperature = temp;
        humidity = hum;
        display();
    }

    void display() {
        std::cout << "Current conditions: " << temperature << "°C and " << humidity << "% humidity\n";
    }
};

// 具体观察者------显示设备2
class StatisticsDisplay : public Observer {
private:
    float maxTemp = -1000;
    float minTemp = 1000;
    float tempSum = 0;
    int numReadings = 0;

public:
    void update(float temp, float hum) override {
        tempSum += temp;
        numReadings++;
        if (temp > maxTemp) maxTemp = temp;
        if (temp < minTemp) minTemp = temp;
        display();
    }

    void display() {
        std::cout << "Avg/Max/Min temperature = " << (tempSum / numReadings)
                  << "/" << maxTemp << "/" << minTemp << "\n";
    }
};

int main() {
    WeatherData weatherData;

    CurrentConditionsDisplay currentDisplay;
    StatisticsDisplay statsDisplay;

    // 注册观察者
    weatherData.registerObserver(&currentDisplay);
    weatherData.registerObserver(&statsDisplay);

    // 模拟数据变化
    weatherData.setMeasurements(25.0f, 65.0f);
    weatherData.setMeasurements(27.0f, 70.0f);
    weatherData.setMeasurements(23.0f, 90.0f);

    // 移除观察者后数据变化
    weatherData.removeObserver(&currentDisplay);
    weatherData.setMeasurements(26.0f, 80.0f);

    return 0;
}

状态模式(State Pattern)

将对象的状态封装到独立的状态类中,并通过状态类切换来改变对象的行为。这样即使状态变化导致行为变化,也不会引起客户端代码的改变,这个设计模式最典型的是TCP连接过程。

UML类图

  • ClosedStateListenStateEstablishedStateTcpState继承关系 ,使用的是空心三角箭头(空心箭头),箭头从子类指向父类。
  • TcpConnection各TcpState子类依赖关系 ,使用的是虚线箭头,箭头指向被依赖对象。

代码示例

cpp 复制代码
#include <iostream>
#include <memory>

// 前向声明
class TcpState;

// 环境类
class TcpConnection {
public:
    TcpConnection(std::shared_ptr<TcpState> state) : state_(state) {}

    void setState(std::shared_ptr<TcpState> state) {
        state_ = state;
    }

    void open() {state_->open(*this);}
    void close() {state_->close(*this);}
    void acknowledge() {state_->acknowledge(*this);}

private:
    std::shared_ptr<TcpState> state_;
};

// 抽象状态接口
class TcpState {
public:
    virtual ~TcpState() = default;

    virtual void open(TcpConnection& connection) = 0;
    virtual void close(TcpConnection& connection) = 0;
    virtual void acknowledge(TcpConnection& connection) = 0;
};

// 具体状态:Closed
class ClosedState : public TcpState {
public:
    void open(TcpConnection& connection) override {
        std::cout << "打开连接,进入监听状态\n";
        connection.setState(std::make_shared<ListenState>());
    }

    void close(TcpConnection& /*connection*/) override {
        std::cout << "连接已经关闭\n";
    }

    void acknowledge(TcpConnection& /*connection*/) override {
        std::cout << "连接关闭,无法接收确认\n";
    }
};

// 具体状态:Listen
class ListenState : public TcpState {
public:
    void open(TcpConnection& connection) override {
        std::cout << "连接建立,进入已建立状态\n";
        connection.setState(std::make_shared<EstablishedState>());
    }

    void close(TcpConnection& connection) override {
        std::cout << "关闭连接,进入关闭状态\n";
        connection.setState(std::make_shared<ClosedState>());
    }

    void acknowledge(TcpConnection& /*connection*/) override {
        std::cout << "监听状态,等待连接建立\n";
    }
};

// 具体状态:Established
class EstablishedState : public TcpState {
public:
    void open(TcpConnection& /*connection*/) override {
        std::cout << "连接已建立,不能重新打开\n";
    }

    void close(TcpConnection& connection) override {
        std::cout << "关闭连接,进入关闭状态\n";
        connection.setState(std::make_shared<ClosedState>());
    }

    void acknowledge(TcpConnection& /*connection*/) override {
        std::cout << "接收确认数据\n";
    }
};

// 测试主函数
int main() {
    auto closed = std::make_shared<ClosedState>();
    TcpConnection connection(closed);

    connection.open();        // Closed -> Listen
    connection.acknowledge(); // Listen状态,等待连接建立
    connection.open();        // Listen -> Established
    connection.acknowledge(); // Established 接收确认数据
    connection.close();       // Established -> Closed
    connection.close();       // 已关闭状态,无法关闭

    return 0;
}

策略模式(Strategy Pattern)

它定义了一系列算法,把它们一个个封装起来,并使它们可以互相替换。策略模式让算法独立于使用它的客户而变化。策略模式的核心意图:

  • 将算法族封装起来,使它们可以互换。
  • 策略模式让算法独立于使用它的客户端独立变化。
  • 客户端在运行时可以自由选择具体策略实现。

UML类图

  • NoDiscountFullReductionPercentageDiscountDiscountStrategy继承关系 ,使用的是空心三角箭头(空心箭头),箭头从子类指向父类。
  • ShoppingCarts各DiscountStrategy子类依赖关系 ,使用的是虚线箭头,箭头指向被依赖对象。

代码示例

cpp 复制代码
#include <iostream>
#include <memory>

// 抽象策略类
class DiscountStrategy {
public:
    virtual ~DiscountStrategy() = default;
    virtual double calculate(double price) const = 0;
};

// 具体策略类 - 无折扣
class NoDiscount : public DiscountStrategy {
public:
    double calculate(double price) const override {
        return price;
    }
};

// 具体策略类 - 满减(如满100减20)
class FullReduction : public DiscountStrategy {
public:
    double calculate(double price) const override {
        if (price >= 100.0)
            return price - 20.0;
        return price;
    }
};

// 具体策略类 - 打折(如打8折)
class PercentageDiscount : public DiscountStrategy {
public:
    PercentageDiscount(double discount) : discount_(discount) {}
    
    double calculate(double price) const override {
        return price * discount_;
    }

private:
    double discount_; // 0.8 表示打8折
};

// 上下文类
class ShoppingCart {
public:
    void setDiscountStrategy(std::shared_ptr<DiscountStrategy> strategy) {
        strategy_ = strategy;
    }

    double calculatePrice(double price) const {
        if (strategy_) {
            return strategy_->calculate(price);
        }
        return price;  // 默认无折扣
    }

private:
    std::shared_ptr<DiscountStrategy> strategy_;
};

int main() {
    ShoppingCart cart;

    double originalPrice = 120.0;
    std::cout << "原价: " << originalPrice << "\n";

    // 使用无折扣策略
    cart.setDiscountStrategy(std::make_shared<NoDiscount>());
    std::cout << "无折扣价: " << cart.calculatePrice(originalPrice) << "\n";

    // 使用满减策略
    cart.setDiscountStrategy(std::make_shared<FullReduction>());
    std::cout << "满减价: " << cart.calculatePrice(originalPrice) << "\n";

    // 使用打折策略(8折)
    cart.setDiscountStrategy(std::make_shared<PercentageDiscount>(0.8));
    std::cout << "打折价: " << cart.calculatePrice(originalPrice) << "\n";

    return 0;
}
相关推荐
随意起个昵称3 小时前
【递归】二进制字符串中的第K位
c++·算法
快乐非自愿3 小时前
常用设计模式:工厂方法模式
javascript·设计模式·工厂方法模式
mjhcsp4 小时前
C++ 循环结构:控制程序重复执行的核心机制
开发语言·c++·算法
Mr_WangAndy4 小时前
C++_chapter15_C++重要知识点_lambda,initializer_list
c++·lambda·初始化列表
Maple_land4 小时前
第1篇:Linux工具复盘上篇:yum与vim
linux·运维·服务器·c++·centos
hggngx548h5 小时前
有哪些C++20特性可以在Dev-C++中使用?
开发语言·c++·c++20
计科土狗6 小时前
算法基础入门第一章
c++·算法
9ilk6 小时前
【仿RabbitMQ的发布订阅式消息队列】 ---- 功能测试联调
linux·服务器·c++·分布式·学习·rabbitmq
北冥湖畔的燕雀6 小时前
std之list
数据结构·c++·list