6个设计模式不够用了,我又开始用它们两个了

您好,我是昊天,国内某头部音频公司的C++主程,多年的音视频开发经验,熟悉Qt、FFmpeg、OpenGL。如果你对这些感兴趣,欢迎关注我的公众号

看过之前文章的读者朋友都知道,我之前写过一篇文章用于介绍我常用的6个设计模式,见链接:我常用的六种设计模式 但是随着项目的深入,这6种设计模式不够用了,最近在项目中,我又开始使用另外两种设计模式:原型模式状态模式

  • • 原型模式:可以实现对象的运行时复制;
  • • 状态模式:简化了对象的状态管理,减少了if else的嵌套,提升了代码的可读性。

今天,我就来分享一下这两种设计模式。

1 原型模式

1.1 定义

原型模式(Prototype Pattern)是一种创建型设计模式,它通过复制现有的对象来创建新对象,而不是通过 new 或构造函数去创建。实现方式为提供clone()方法借助对象当前的实时数据来生成新的对象,而不是从头开始创建。

1.2 应用场景

原型模式适用于以下场景:

  • • 需要借助现有对象的数据生成新对象;
  • • 频繁创建相似对象(比如游戏中生成相似的敌人或道具)。
  • • 对象配置固定,复制比重新构造更灵活。

比如存在一个多层嵌套的数据结构(省市县乡),每次都 new 一份太麻烦。这时候就可以用原型模式来快速复制一份模板。

1.3 代码实现

下面是一个 C++ 示例:

代码语言:javascript代码运行次数:0运行复制
#include <iostream>
#include <memory>
#include <string>

// 游戏角色基类
classCharacter {
public:
    Character(const std::string& name, int level, int hp, int attack)
        : name_(name), level_(level), hp_(hp), attack_(attack) {}
    virtual ~Character() = default;
    
    // 克隆接口
    virtual std::unique_ptr<Character> clone() const = 0;
    
    // 显示角色信息
    virtual void display() const {
        std::cout << "角色名称: " << name_
                  << "\n等级: " << level_
                  << "\n生命值: " << hp_
                  << "\n攻击力: " << attack_ << "\n";
    }
    
    // 修改属性的方法
    void levelUp() { ++level_; }
    void setHP(int hp) { hp_ = hp; }

protected:
    std::string name_;
    int level_;
    int hp_;
    int attack_;
};

// 战士类
classWarrior : public Character {
public:
    Warrior(const std::string& name, int level, int hp, int attack, int defense)
        : Character(name, level, hp, attack), defense_(defense) {}
    
    // 实现克隆方法
    std::unique_ptr<Character> clone() const override {
        return std::make_unique<Warrior>(*this);
    }
    
    // 重写显示方法,添加防御力显示
    void display() const override {
        Character::display();
        std::cout << "防御力: " << defense_ << "\n";
    }

private:
    int defense_;
};

// 使用示例
void testGameCharacter() {
    // 创建一个原型战士
    auto warrior = std::make_unique<Warrior>("勇士A", 1, 100, 20, 10);
    std::cout << "原始角色:\n";
    warrior->display();
    
    // 克隆一个新战士
    auto clonedWarrior = warrior->clone();
    std::cout << "\n克隆角色:\n";
    clonedWarrior->display();
    
    // 修改克隆角色的属性
    clonedWarrior->levelUp();
    clonedWarrior->setHP(150);
    
    std::cout << "\n修改后的克隆角色:\n";
    clonedWarrior->display();
}

/* 输出示例:
原始角色:
角色名称: 勇士A
等级: 1
生命值: 100
攻击力: 20
防御力: 10

克隆角色:
角色名称: 勇士A
等级: 1
生命值: 100
攻击力: 20
防御力: 10

修改后的克隆角色:
角色名称: 勇士A
等级: 2
生命值: 150
攻击力: 20
防御力: 10
*/

2 状态模式

2.1 定义

状态模式(State Pattern)是一种行为型设计模式,其主要用于状态和行为强关联的场景中——对象状态的改变会影响行为

状态模式将对象的行为封装在不同的状态类中,每个状态类都实现了相同的接口,这样就可以在运行时动态地改变对象的行为。

2.2 应用场景

状态模式适用于以下场景:

  • • 对象行为依赖于状态,且状态频繁变化。
  • • 用大量 if-else/switch 判断状态时,代码难维护。
  • • 状态逻辑复杂,想做到“高内聚、低耦合”。

比如:订单流程管理(待支付 → 已支付 → 已发货 → 已签收)、视频播放器(播放、暂停、停止)等等。

2.3 代码实现

下面是一个简化的视频播放器状态切换例子:

代码语言:javascript代码运行次数:0运行复制
#include <iostream>
#include <memory>

// 前向声明
classPlayer;

// 状态接口
classState {
public:
    virtual ~State() {}
    virtual void handle(Player& player) = 0;
    virtual const char* name() const = 0;
};

// 播放器上下文
classPlayer {
public:
    Player(std::unique_ptr<State> state) : state_(std::move(state)) {}

    void setState(std::unique_ptr<State> state) {
        state_ = std::move(state);
    }

    void request() {
        state_->handle(*this);
    }

    void printState() {
        std::cout << "Current State: " << state_->name() << "\n";
    }

private:
    std::unique_ptr<State> state_;
};

// 具体状态
classPlaying : public State {
public:
    void handle(Player& player) override;
    const char* name() const override { return"Playing"; }
};

classPaused : public State {
public:
    void handle(Player& player) override;
    const char* name() const override { return"Paused"; }
};

void Playing::handle(Player& player) {
    std::cout << "Now pausing...\n";
    player.setState(std::make_unique<Paused>());
}

void Paused::handle(Player& player) {
    std::cout << "Now resuming play...\n";
    player.setState(std::make_unique<Playing>());
}

// 使用
void testState() {
    Player player(std::make_unique<Paused>());
    player.printState();
    player.request(); // 切换状态
    player.printState();
    player.request(); // 切换回去
    player.printState();
}
//输出:
Current State: Paused
Now resuming play...
Current State: Playing
Now pausing...
Current State: Paused

是不是比 if-else 看起来清爽多了?

3 实战建议

  • • 原型模式通常不被显式“设计”,而是隐式出现在那些缓存对象模板或运行时复制的场景中。切记不要滥用该模式,不是所有 new 都要 clone。如果对象创建简单,直接 new 更直观,原型模式更多用于性能敏感或结构复杂的对象
  • • 状态模式是典型的“重构利器”。当你看到满屏的 if (state == XXX) 时,就该考虑是不是可以把它们“对象化”

4 总结

本文介绍了两种设计模式:原型模式和状态模式。一个负责建,一个负责变。灵活应用不仅可以提高代码的可维护性,还可以提升代码的性能。但是,设计模式不是随处可用的锤子,需要根据实际情况进行选择。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。原始发表:2025-04-11,如有侵权请联系 cloudcommunity@tencent 删除std对象接口设计模式原型