Loading [MathJax]/jax/input/TeX/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >6个设计模式不够用了,我又开始用它们两个了

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

作者头像
程序员的园
发布于 2025-04-13 09:16:56
发布于 2025-04-13 09:16:56
10000
代码可运行
举报
运行总次数:0
代码可运行

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

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

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

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

1 原型模式

1.1 定义

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

1.2 应用场景

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

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

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

1.3 代码实现

下面是一个 C++ 示例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#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
运行
AI代码解释
复制
#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.com 删除

本文分享自 程序员的园 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
大话设计模式08-状态模式-2020-9-24
状态模式:当一个对象的内在状态允许改变其行为,这个对象看起来好像改变了其类。主要用于一个对象的状态转换很复杂时,即含有大量的if else 语句时,可以将状态判断逻辑转移到表示不同状态的类中。这样要增加新状态变化时,只需要新增子类和修改部分类,不同修改整个判断函数。UML类图如下:
用户7719114
2022/02/22
2590
大话设计模式08-状态模式-2020-9-24
原型模式概述
原型模式(Prototype Pattern)是一种创建型设计模式,它允许通过复制已有对象来创建新对象,而不是直接通过实例化类来创建。 这种模式提供了一种创建对象的快捷方式,尤其适用于对象创建成本高或需要深复制的场景。
码事漫谈
2024/12/20
1380
原型模式概述
设计模式-原型模式
在原型模式中,原型对象作为一个模板,包含了要复制的对象的所有属性和方法。当需要创建一个新的对象时,只需通过克隆原型对象来获得一个完全相同的新对象。
啊QQQQQ
2025/04/16
680
设计模式-原型模式
《设计模式:可复用面向对象软件的基础》学习并理解 23 种设计模式
设计模式 Design Pattern 是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结,使用设计模式是为了可重用代码、让代码更容易被他人理解并且保证代码可靠性。。
网罗开发
2021/01/29
4.1K0
《设计模式:可复用面向对象软件的基础》学习并理解 23 种设计模式
23种设计模式之备忘录模式
游戏角色有攻击力和防御力,在大战boss之前保存自身的状态(攻击力血量等等),当大战boss后攻击力和防御力下降,从备忘录对象恢复到大战前的状态
暴躁的程序猿
2022/03/23
2290
状态模式详解
状态模式(State Pattern)是一种行为设计模式,它允许一个对象在其内部状态改变时改变其行为,使其看起来像改变了自身的类。通过将状态相关的行为抽取到独立的状态类中,状态模式能有效实现状态与行为的分离。
码事漫谈
2024/12/20
970
状态模式详解
Java设计模式之备忘录模式
说明:如果希望保存多个originator对象的不同时间的状态,也可以,只需要要 HashMap <String, 集合>
shaoshaossm
2022/12/27
3460
Java设计模式之备忘录模式
C++设计模式 - 原型模式
原型模式是一种创建型设计模式,其功能为复制一个运行时的对象,包括对象各个成员当前的值。而代码又能保持独立性。
开源519
2021/11/18
3140
C++设计模式 - 原型模式
设计模式之原型模式(创建型)
原型模式(Prototype Pattern):原型模式是提供一个原型接口,提供原型的克隆,创建新的对象,是一种对象创建型模式。
SmileNicky
2019/03/06
3580
备忘录设计模式解读
游戏角色有攻击力和防御力,在大战 Boss 前保存自身的状态(攻击力和防御力),当大战 Boss 后攻击力和防御力下降,从备忘录对象恢复到大战前的状态
一个风轻云淡
2023/10/15
1850
备忘录设计模式解读
设计模式-模版方法
借助抽象类定义算法的骨架,再由具体子类实现算法的特定步骤。这种设计模式让算法的整体结构得以固定,同时又能让不同的子类灵活地实现具体步骤;
啊QQQQQ
2025/04/09
720
设计模式-模版方法
06-07-设计模式 备忘录模式
游戏角色有攻击力和防御力,在大战Boss前保存自身的状态(攻击力和防御力),当大战Boss后攻击力和防御力下降,从备忘录对象恢复到大战前的状态
彼岸舞
2022/05/28
1400
06-07-设计模式 备忘录模式
图解Java设计模式之备忘录模式
游戏角色有攻击力和防御力,在大战Boss前保存自身的状态(攻击力和防御力),当大战Boss后攻击力和防御力下降,从备忘录对象恢复到大战前的状态。
海仔
2020/04/08
7770
图解Java设计模式之备忘录模式
GoF 23种经典的设计模式——原型模式
原型模式(Prototype Pattern)是一种创建型设计模式,其主要思想是通过复制(克隆)现有对象来创建新的对象,而不是通过构造函数创建。这样可以避免重复创建相似对象时的性能损耗,同时也更灵活,可以动态地添加或删除对象。原型模式的性能优势主要来自于避免了重复的初始化和构造过程。在原型模式中,对象的克隆是通过复制已有对象的数据而不是重新构造对象,因此避免了重复的初始化和资源获取操作,提高了性能。
Andromeda
2024/01/16
1510
GoF 23种经典的设计模式——原型模式
游戏开发设计模式之原型模式
原型模式(Prototype Pattern)是一种创建型设计模式,它允许通过复制现有对象来创建新对象,而无需了解其具体类。这种模式在游戏开发中非常有用,因为游戏通常涉及大量的对象,这些对象可能具有相似的属性和行为。
用户11315985
2024/10/16
1370
游戏开发设计模式之原型模式
设计模式之原型模式(Prototype 模式)
原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
海盗船长
2021/12/07
3980
设计模式之原型模式(Prototype 模式)
设计模式之桥梁模式
也许你在很多的代码中见过成员叫做_pImpl或者xxxImpl, 然后一个方法的实现为如下代码所示,比如方法为DoSomething中调用了成员的同名方法DoSomething()(有时候也是会有额外的一些处理代码),这个时候可能就是使用了设计模式之桥梁模式 (Bridge Pattern)。
河边一枝柳
2022/06/21
3840
设计模式之桥梁模式
设计模式(二十二):行为型之备忘录模式
Java微观世界
2025/01/21
1110
设计模式(二十二):行为型之备忘录模式
建造者模式
建造者模式(Builder Pattern)是一种创建型设计模式,它通过将对象的构造与表示分离,使得同样的构建过程可以创建不同的对象。
码事漫谈
2024/12/20
1080
建造者模式
设计模式-工厂模式
工厂模式是一种设计模式,用于创建对象实例的方法。它通过定义一个用于创建对象的接口,但让子类决定实例化哪个类来创建对象。这种模式使得一个类的实例化延迟到子类中,从而让子类来决定创建哪个类的实例。
啊QQQQQ
2025/04/11
510
设计模式-工厂模式
相关推荐
大话设计模式08-状态模式-2020-9-24
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验