您好,我是昊天,国内某头部音频公司的C++主程,多年的音视频开发经验,熟悉Qt、FFmpeg、OpenGL。如果你对这些感兴趣,欢迎关注我的公众号
看过之前文章的读者朋友都知道,我之前写过一篇文章用于介绍我常用的6个设计模式,见链接:我常用的六种设计模式 但是随着项目的深入,这6种设计模式不够用了,最近在项目中,我又开始使用另外两种设计模式:原型模式和状态模式。
今天,我就来分享一下这两种设计模式。
原型模式(Prototype Pattern)是一种创建型设计模式,它通过复制现有的对象来创建新对象,而不是通过 new 或构造函数去创建。实现方式为提供clone()
方法借助对象当前的实时数据来生成新的对象,而不是从头开始创建。
原型模式适用于以下场景:
比如存在一个多层嵌套的数据结构(省市县乡),每次都 new 一份太麻烦。这时候就可以用原型模式来快速复制一份模板。
下面是一个 C++ 示例:
#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
*/
状态模式(State Pattern)是一种行为型设计模式,其主要用于状态和行为强关联的场景中——对象状态的改变会影响行为。
状态模式将对象的行为封装在不同的状态类中,每个状态类都实现了相同的接口,这样就可以在运行时动态地改变对象的行为。
状态模式适用于以下场景:
比如:订单流程管理(待支付 → 已支付 → 已发货 → 已签收)、视频播放器(播放、暂停、停止)等等。
下面是一个简化的视频播放器状态切换例子:
#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 看起来清爽多了?
本文介绍了两种设计模式:原型模式和状态模式。一个负责建,一个负责变。灵活应用不仅可以提高代码的可维护性,还可以提升代码的性能。但是,设计模式不是随处可用的锤子,需要根据实际情况进行选择。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有