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对象接口设计模式原型
发布评论