设计模式之状态模式 (C++ 实现)

ops/2024/11/13 9:46:48/

设计模式是软件开发中的一项重要技能,它提供了一种通用的解决方案以应对不同的设计问题。状态模式是一种行为型设计模式,适用于对象在不同状态下表现出不同的行为。通过实现状态模式,可以让代码更清晰、更易扩展与维护。本文将通过C++实现状态模式,并通过实际案例帮助读者理解。

2. 设计模式概述

2.1 什么是设计模式

设计模式是软件设计中的一种最佳实践,提供解决特定类型问题的标准方式。设计模式不依赖于特定的编程语言,因此可以在任何编程语言中实现。根据著作《设计模式:可复用面向对象软件的基础》中的分类,设计模式主要分为三类:

  • 创建型模式
  • 结构型模式
  • 行为型模式

状态模式属于行为型模式。

2.2 状态模式简介

状态模式允许一个对象在其内部状态改变时改变其行为。对象看起来像是改变了其类。使用状态模式可以将状态的相关行为放在各个状态类中,从而实现状态切换的灵活性和可扩展性。

3. 状态模式的定义

3.1 状态模式的组成部分

状态模式主要由以下几个部分构成:

  1. Context (上下文):持有一个具体的状态对象,并在状态之间切换。
  2. State (状态接口):定义一个接口用于在具体状态中实现不同的行为。
  3. ConcreteState (具体状态):实现状态接口的具体类,每个状态都有自己的行为。

3.2 状态模式的优缺点

优点

  • 将状态和行为分离,减少了代码中的复杂性。
  • 通过引入新的状态类,易于扩展,而不需要修改原有代码。
  • 可以简化多重条件判断流程。

缺点

  • 状态类的数量可能较多,增加管理复杂度。
  • 状态与上下文之间的耦合关系可能会导致代码难以维护。

4. C++实现状态模式

4.1 经典案例:电动门

我们通过电动门的状态管理来展示状态模式的使用。电动门可以有两种状态:打开和关闭。每种状态都有不同的行为,如打开门时触发的行为和关闭门时触发的行为。

4.2 代码实现

下例展示了如何使用状态模式实现电动门的行为。

1. 定义状态接口

// State.h
#ifndef STATE_H
#define STATE_Hclass DoorState; // 前向声明class Door {
public:
virtual void open() = 0;
virtual void close() = 0;
virtual void setState(DoorState* state) = 0;
};class DoorState {
public:
virtual ~DoorState() {}
virtual void open(Door* door) = 0;
virtual void close(Door* door) = 0;
};#endif // STATE_H

2. 实现具体状态

// OpenState.h
#ifndef OPENSTATE_H
#define OPENSTATE_H#include "State.h"
#include <iostream>class OpenState : public DoorState {
public:
void open(Door* door) override {
std::cout << "The door is already open!" << std::endl;
}void close(Door* door) override {
std::cout << "Closing the door..." << std::endl;
// 改变状态
door->setState(new ClosedState());
}
};// ClosedState.h
#ifndef CLOSEDSTATE_H
#define CLOSEDSTATE_H#include "State.h"
#include <iostream>class ClosedState : public DoorState {
public:
void open(Door* door) override {
std::cout << "Opening the door..." << std::endl;
// 改变状态
door->setState(new OpenState());
}void close(Door* door) override {
std::cout << "The door is already closed!" << std::endl;
}
};#endif // CLOSEDSTATE_H

3. 实现上下文

// DoorImpl.h
#ifndef DOORIMPL_H
#define DOORIMPL_H#include "State.h"
#include "OpenState.h"
#include "ClosedState.h"class DoorImpl : public Door {
private:
DoorState* state;public:
DoorImpl() {
state = new ClosedState(); // 初始状态
}~DoorImpl() {
delete state;
}void setState(DoorState* newState) override {
delete state; // 删除旧状态
state = newState; // 更换状态
}void open() override {
state->open(this);
}void close() override {
state->close(this);
}
};#endif // DOORIMPL_H

4. 主函数

// main.cpp
#include "DoorImpl.h"int main() {
Door* door = new DoorImpl();door->open(); // 输出:Opening the door...
door->close(); // 输出:Closing the door...
door->close(); // 输出:The door is already closed!door->open(); // 输出:Opening the door...
door->open(); // 输出:The door is already open!delete door; // 清理资源
return 0;
}

4.3 状态管理逻辑

在这个电动门的例子中,DoorImpl表示门的上下文,它根据状态类的行为决定运行哪个方法。具体的打开和关闭行为由OpenStateClosedState类实现。

5. 扩展案例:音乐播放器

5.1 需求分析

让我们进一步扩展,创建一个音乐播放器的状态管理。音乐播放器可以有以下状态:

  • 停止
  • 播放
  • 暂停

每种状态下,播放器的行为会有所不同,例如在播放状态时,用户可以选择暂停或停止,而在停止状态时,用户只能选择播放。

5.2 状态模式的实现步骤

  1. 定义状态接口及其实现。
  2. 编写上下文类,管理状态切换。
  3. 在主函数中模拟播放器的行为。

5.3 完整代码示例

1. 定义状态接口

// MusicPlayerState.h
#ifndef MUSICPLAYERSTATE_H
#define MUSICPLAYERSTATE_Hclass MusicPlayer;class MusicPlayerState {
public:
virtual ~MusicPlayerState() {}
virtual void play(MusicPlayer* player) = 0;
virtual void pause(MusicPlayer* player) = 0;
virtual void stop(MusicPlayer* player) = 0;
};#endif // MUSICPLAYERSTATE_H

2. 实现具体状态

// PlayingState.h
#ifndef PLAYINGSTATE_H
#define PLAYINGSTATE_H#include "MusicPlayerState.h"
#include <iostream>class PlayingState : public MusicPlayerState {
public:
void play(MusicPlayer* player) override {
std::cout << "Already playing!" << std::endl;
}void pause(MusicPlayer* player) override {
std::cout << "Pausing..." << std::endl;
player->setState(new PausedState());
}void stop(MusicPlayer* player) override {
std::cout << "Stopping..." << std::endl;
player->setState(new StoppedState());
}
};// PausedState.h
#ifndef PAUSEDSTATE_H
#define PAUSEDSTATE_H#include "MusicPlayerState.h"
#include <iostream>class PausedState : public MusicPlayerState {
public:
void play(MusicPlayer* player) override {
std::cout << "Resuming playback..." << std::endl;
player->setState(new PlayingState());
}void pause(MusicPlayer* player) override {
std::cout << "Already paused!" << std::endl;
}void stop(MusicPlayer* player) override {
std::cout << "Stopping..." << std::endl;
player->setState(new StoppedState());
}
};// StoppedState.h
#ifndef STOPPEDSTATE_H
#define STOPPEDSTATE_H#include "MusicPlayerState.h"
#include <iostream>class StoppedState : public MusicPlayerState {
public:
void play(MusicPlayer* player) override {
std::cout << "Starting playback..." << std::endl;
player->setState(new PlayingState());
}void pause(MusicPlayer* player) override {
std::cout << "Can't pause, music is stopped!" << std::endl;
}void stop(MusicPlayer* player) override {
std::cout << "Already stopped!" << std::endl;
}
};#endif // STOPPEDSTATE_H

3. 实现上下文

// MusicPlayer.h
#ifndef MUSICPLAYER_H
#define MUSICPLAYER_H#include "MusicPlayerState.h"
#include "StoppedState.h"class MusicPlayer {
private:
MusicPlayerState* state;public:
MusicPlayer() {
state = new StoppedState(); // 初始状态
}~MusicPlayer() {
delete state;
}void setState(MusicPlayerState* newState) {
delete state;
state = newState;
}void play() {
state->play(this);
}void pause() {
state->pause(this);
}void stop() {
state->stop(this);
}
};#endif // MUSICPLAYER_H

3. 主函数

// main.cpp
#include "MusicPlayer.h"int main() {
MusicPlayer* player = new MusicPlayer();player->play(); // 输出:Starting playback...
player->pause(); // 输出:Pausing...
player->stop(); // 输出:Stopping...
player->play(); // 输出:Starting playback...delete player; // 清理资源
return 0;
}

在这篇指南中,我们深入探讨了状态模式的概念和结构,通过电动门和音乐播放器的实例实现了状态模式,通过C++代码展现了状态切换的灵活性与可扩展性。状态模式是一个非常实用的设计模式,有助于我们在需要处理对象状态变化时,将状态逻辑封装到不同的类中,从而使代码更清晰,更易于管理和维护。

展望未来状态模式在实际工作中应用广泛,尤其是在复杂的对象状态管理中,如游戏开发、网络协议处理、用户界面等领域。掌握状态模式,不仅能提高我们的编码效率,还有助于我们设计出更具可维护性的系统。


http://www.ppmy.cn/ops/108130.html

相关文章

Spring6梳理7——依赖注入之特殊类型属性

目录 ①字面量赋值 ②null值 ③xml实体 ④CDATA节 ①字面量赋值 什么是字面量&#xff1f; int a10; 字面量是在源代码中用来表示固定值的表示法。几乎所有的计算机编程语言都支持基本值的字面量表示&#xff0c;例如整数、浮点数和字符串。许多语言还支持布尔类…

在亚马逊云科技上利用Agent和生成式AI写小说(下篇)

今天小李哥将继续介绍亚马逊推出的国际前沿人工智能AI大模型平台Amazon Bedrock上的Agent的功能。我们将利用Agent结合应用代码工作流服务Step Functions创建链式提示词&#xff08;Prompt Chaining&#xff09;&#xff0c;通过提示词执行一系列调用Amazon Bedrock上AI大模型的…

Scikit-learn与TensorFlow哪个好

Scikit-learn 和 TensorFlow 是两款非常流行的机器学习库&#xff0c;但它们适合的使用场景不同&#xff0c;取决于任务的复杂性和需求。让我们比较一下它们的特点&#xff0c;帮助你选择合适的工具。 1. Scikit-learn Scikit-learn 是一个经典的机器学习库&#xff0c;主要用…

C++:类与对象

一、面向对象编程 (一) 面向过程vs面向对象 面向过程&#xff08;Procedural-Oriented-Programming&#xff0c; POP&#xff09;和面向对象&#xff08;Object-Oriented-Programming&#xff0c;OOP&#xff09;&#xff0c;是两种典型的编程范式&#xff0c;通常是作为划分编…

深入理解Docker核心原理:全面解析Docker Client

随着云计算与容器技术的飞速发展&#xff0c;Docker已经成为软件开发、部署和运维中的重要工具之一。在Docker的架构中&#xff0c;Docker Client作为用户操作Docker系统的接口&#xff0c;起着至关重要的作用。本文将详细解析Docker Client的核心原理、工作机制、常用命令以及…

jenkins工具的介绍和gitlab安装

使用方式 替代手动&#xff0c;自动化拉取、集成、构建、测试&#xff1b;是CI/CD持续集成、持续部署主流开发模式中重要工具&#xff1b;必须组件 jenkins-gitlab&#xff0c;代码公共仓库服务器&#xff08;至少6G内存&#xff09;&#xff1b;jenkins-server&#xff0c;需…

lodash

下载npm i lodash //数据二次处理 const monthGroup useMemo(() > {//return 出去计算后的值return _.groupBy(billList, item > dayjs(item.date).format(YYYY-MM)) }, [billList]) 拿到当前月份 //单日统计列表 const dayGroup useMemo(() > {const group _.g…

HUAWEI华为MateBook B5-420 i5 集显(KLCZ-WXX9,KLCZ-WDH9)原装出厂Windows10系统文件下载

适用型号&#xff1a;KLCZ-WXX9、KLCZ-WDH9 链接&#xff1a;https://pan.baidu.com/s/12xnaLtcPjZoyfCcJUHynVQ?pwdelul 提取码&#xff1a;elul 华为原装系统自带所有驱动、出厂主题壁纸、系统属性联机支持标志、系统属性专属LOGO标志、华为浏览器、Office办公软件、华为…