在C++设计模式中,状态模式(State Pattern)是一种行为设计模式,它允许对象在内部状态改变时改变其行为,使对象看起来似乎修改了其类。状态模式的主要动机、意图和适用场合如下:
动机
在面向对象的设计中,对象的行为往往依赖于其状态。传统的实现方式是在对象中使用大量的条件语句来检查状态并执行相应的操作。这种做法有以下几个问题:
- 代码复杂性:随着状态的增多,条件语句会变得越来越复杂,难以维护。
- 可扩展性差:添加新状态时,需要修改现有的条件语句,违反了开闭原则(对扩展开放,对修改关闭)。
- 状态转移不清晰:状态之间的转移逻辑分散在各个地方,不便于管理和理解。
为了解决这些问题,状态模式应运而生。
意图
状态模式的意图是将对象的状态抽象成类层次结构,并将行为封装在这些状态类中。具体来说:
- 定义一个状态接口,该接口声明了所有可能状态共有的操作。
- 为每种状态实现一个具体的类,每个类都实现了状态接口中的操作,并在必要时处理状态转换。
- 维护一个当前状态的引用,主体对象通过这个引用委托给当前状态对象执行相应的操作。
通过这种方式,状态模式将状态相关的逻辑从主体类中分离出来,使得代码更加清晰、模块化,并且易于扩展。
适用场景
状态模式适用于以下情况:
- 对象行为依赖于其状态,且需要根据状态改变行为。
- 状态之间有复杂的转移逻辑,需要明确地定义状态转换规则。
- 希望将状态相关的代码集中管理,提高代码的可维护性和可扩展性。
- 需要对不同的状态进行不同的操作,并且这些操作可能涉及复杂的业务逻辑。
例如,一个自动售货机可以根据其当前状态(如待支付、已支付、缺货等)执行不同的操作,如接收硬币、发放商品、退还余额等。使用状态模式可以清晰地定义每种状态下的行为以及状态之间的转换。
示例代码
以下是一个简单的C++示例,展示了状态模式的使用:
cpp
#include <iostream>
#include <memory>
// 状态接口
class State {
public:
virtual void handle(const std::string& input) = 0;
virtual ~State() = default;
};
// 具体状态A
class StateA : public State {
public:
void handle(const std::string& input) override {
std::cout << "StateA handles: " << input << std::endl;
// 可能会转换到其他状态
}
};
// 具体状态B
class StateB : public State {
public:
void handle(const std::string& input) override {
std::cout << "StateB handles: " << input << std::endl;
// 可能会转换到其他状态
}
};
// 主体类
class Context {
public:
void setState(std::shared_ptr<State> state) {
currentState = state;
}
void request(const std::string& input) {
if (currentState) {
currentState->handle(input);
}
}
private:
std::shared_ptr<State> currentState;
};
int main() {
// 创建具体状态实例
auto stateA = std::make_shared<StateA>();
auto stateB = std::make_shared<StateB>();
// 创建上下文并设置初始状态
Context context;
context.setState(stateA);
// 处理请求
context.request("Initial request");
// 转换状态
context.setState(stateB);
context.request("Another request");
return 0;
}
在这个示例中,Context
类维护了一个 State
接口的指针,并将处理请求委托给当前状态对象。不同的状态类 (StateA
和 StateB
) 实现了不同的处理逻辑。通过设置不同的状态,Context
对象可以表现出不同的行为。
通过这种方式,状态模式使得状态相关的逻辑更加清晰和模块化,同时也便于添加新的状态而不需要修改现有的代码。
面是一个使用状态模式来模拟Windows PnP(Plug and Play)设备驱动中状态转移的C++示例。我们将定义一个设备驱动类和多个状态类,每个状态类将处理不同状态下的设备行为和状态转移。
状态模式在PnP设备驱动中的应用
- 定义状态接口 :定义一个状态接口
State
,声明所有可能状态共有的操作。 - 实现具体状态类 :为每种状态(如
Unplugged
、PlugIn
、Initialize
、Ready
)实现一个具体的类。 - 维护当前状态 :在
DeviceDriver
类中维护一个当前状态的引用,并根据需要切换状态。
示例代码
cpp
#include <iostream>
#include <memory>
#include <string>
// 状态接口
class State {
public:
virtual ~State() = default;
virtual void onUnplug(DeviceDriver* driver) = 0;
virtual void onPlugIn(DeviceDriver* driver) = 0;
virtual void onInitialize(DeviceDriver* driver) = 0;
virtual void onReady(DeviceDriver* driver) = 0;
};
// 设备驱动类
class DeviceDriver {
public:
DeviceDriver() : currentState(std::make_shared<Unplugged>()) {}
void unplug() {
currentState->onUnplug(this);
}
void plugIn() {
currentState->onPlugIn(this);
}
void initialize() {
currentState->onInitialize(this);
}
void ready() {
currentState->onReady(this);
}
void setState(const std::shared_ptr<State>& state) {
currentState = state;
}
private:
std::shared_ptr<State> currentState;
};
// 具体状态:未插入
class Unplugged : public State {
public:
void onUnplug(DeviceDriver* driver) override {
std::cout << "Already unplugged." << std::endl;
}
void onPlugIn(DeviceDriver* driver) override {
std::cout << "Device plugged in." << std::endl;
driver->setState(std::make_shared<PlugIn>());
}
void onInitialize(DeviceDriver* driver) override {
std::cout << "Cannot initialize. Device not plugged in." << std::endl;
}
void onReady(DeviceDriver* driver) override {
std::cout << "Cannot be ready. Device not plugged in." << std::endl;
}
};
// 具体状态:已插入
class PlugIn : public State {
public:
void onUnplug(DeviceDriver* driver) override {
std::cout << "Device unplugged." << std::endl;
driver->setState(std::make_shared<Unplugged>());
}
void onPlugIn(DeviceDriver* driver) override {
std::cout << "Already plugged in." << std::endl;
}
void onInitialize(DeviceDriver* driver) override {
std::cout << "Device initialized." << std::endl;
driver->setState(std::make_shared<Initialize>());
}
void onReady(DeviceDriver* driver) override {
std::cout << "Cannot be ready. Device not initialized." << std::endl;
}
};
// 具体状态:已初始化
class Initialize : public State {
public:
void onUnplug(DeviceDriver* driver) override {
std::cout << "Device unplugged." << std::endl;
driver->setState(std::make_shared<Unplugged>());
}
void onPlugIn(DeviceDriver* driver) override {
std::cout << "Already plugged in and initialized." << std::endl;
}
void onInitialize(DeviceDriver* driver) override {
std::cout << "Already initialized." << std::endl;
}
void onReady(DeviceDriver* driver) override {
std::cout << "Device is ready to use." << std::endl;
driver->setState(std::make_shared<Ready>());
}
};
// 具体状态:已准备好
class Ready : public State {
public:
void onUnplug(DeviceDriver* driver) override {
std::cout << "Device unplugged." << std::endl;
driver->setState(std::make_shared<Unplugged>());
}
void onPlugIn(DeviceDriver* driver) override {
std::cout << "Device is already ready." << std::endl;
}
void onInitialize(DeviceDriver* driver) override {
std::cout << "Device is already initialized and ready." << std::endl;
}
void onReady(DeviceDriver* driver) override {
std::cout << "Device is already ready." << std::endl;
}
};
int main() {
DeviceDriver driver;
// 模拟设备插拔和状态转移
driver.plugIn();
driver.initialize();
driver.ready();
driver.unplug();
driver.plugIn();
driver.ready();
return 0;
}
代码说明
-
状态接口
State
:- 定义了四个虚函数:
onUnplug
、onPlugIn
、onInitialize
、onReady
,分别对应设备在不同状态下的行为。
- 定义了四个虚函数:
-
设备驱动类
DeviceDriver
:- 维护一个当前状态
currentState
,并提供四个公共方法unplug
、plugIn
、initialize
、ready
,这些方法委托给当前状态对象处理。 - 提供
setState
方法用于切换状态。
- 维护一个当前状态
-
具体状态类:
Unplugged
:设备未插入状态。PlugIn
:设备已插入状态。Initialize
:设备已初始化状态。Ready
:设备已准备好状态。
-
主函数
main
:- 创建一个
DeviceDriver
对象,并模拟设备的插拔和状态转移过程。
- 创建一个
通过这种方式,状态模式使得设备驱动的代码更加模块化和可维护,状态之间的转换也更加清晰
状态模式通常与其他设计模式协同使用,以提高代码的模块化和可维护性。以下是状态模式常见的协同模式及其使用场景:
1. 策略模式 (Strategy Pattern)
- 场景:当不同状态下的行为可以通过不同的算法实现时,可以使用策略模式来定义这些算法。
- 协同方式:状态模式中的每个状态类可以包含一个策略对象,用于实现具体的行为。这样,状态的改变不仅涉及状态的切换,还可以动态改变算法。
- 示例:在状态模式中,不同状态下的设备初始化可以使用不同的初始化策略。
2. 工厂模式 (Factory Pattern)
- 场景:当状态类的创建需要复杂逻辑时,可以使用工厂模式来创建状态对象。
- 协同方式:通过工厂模式,可以在状态切换时动态创建所需的状态对象,而不需要在每个地方重复创建逻辑。
- 示例:使用工厂模式创建设备驱动的初始状态或特定状态。
3. 观察者模式 (Observer Pattern)
- 场景:当状态变化需要通知其他对象时,可以使用观察者模式。
- 协同方式:状态对象可以充当被观察者,其他对象(如日志记录器、UI 更新器等)可以注册为观察者,当状态变化时,观察者会收到通知并作出相应处理。
- 示例:在设备驱动状态变化时,通知UI更新显示状态。
4. 单例模式 (Singleton Pattern)
- 场景:当状态类需要全局唯一实例时,可以使用单例模式。
- 协同方式:状态类可以通过单例模式确保每个状态在整个应用中只有一个实例,这有助于节省资源并确保状态的一致性。
- 示例:确保设备的"未插入"状态在整个应用中只有一个实例。
5. 模板方法模式 (Template Method Pattern)
- 场景:当状态类有共同的骨架方法,但具体实现不同步时,可以使用模板方法模式。
- 协同方式:状态类可以定义一个模板方法,该方法包含一系列步骤,其中某些步骤的具体实现由具体的子类提供。
- 示例 :定义一个模板方法
handleEvent
,该方法包含一系列步骤,如检查前置条件、执行操作、更新状态等,具体状态类可以覆盖这些步骤的实现。
6. 命令模式 (Command Pattern)
- 场景:当状态变化需要记录或撤销时,可以使用命令模式。
- 协同方式:每个状态变化可以封装成一个命令对象,命令对象可以记录状态变化的操作,便于撤回或重做。
- 示例:记录设备状态变化的命令,以便在需要时恢复到之前的状态。
7. 责任链模式 (Chain of Responsibility Pattern)
- 场景:当状态变化需要多个对象处理时,可以使用责任链模式。
- 协同方式:状态变化可以传递给一个链中的多个对象,每个对象根据其职责处理或传递请求。
- 示例:当设备状态变化时,多个处理器(如日志记录器、安全检查器等)可以顺序处理该状态变化。
示例
以下是一个结合状态模式和工厂模式、策略模式的示例:
cpp
#include <iostream>
#include <memory>
#include <string>
// 策略接口
class InitializationStrategy {
public:
virtual void initialize() = 0;
virtual ~InitializationStrategy() = default;
};
// 具体策略:快速初始化
class QuickInitialization : public InitializationStrategy {
public:
void initialize() override {
std::cout << "Quick initialization" << std::endl;
}
};
// 具体策略:完整初始化
class FullInitialization : public InitializationStrategy {
public:
void initialize() override {
std::cout << "Full initialization" << std::endl;
}
};
// 状态接口
class State {
public:
virtual ~State() = default;
virtual void onUnplug(DeviceDriver* driver) = 0;
virtual void onPlugIn(DeviceDriver* driver) = 0;
virtual void onInitialize(DeviceDriver* driver) = 0;
virtual void onReady(DeviceDriver* driver) = 0;
};
// 状态工厂类
class StateFactory {
public:
static std::shared_ptr<State> createUnpluggedState() {
return std::make_shared<Unplugged>();
}
static std::shared_ptr<State> createPlugInState() {
return std::make_shared<PlugIn>();
}
static std::shared_ptr<State> createInitializeState() {
return std::make_shared<Initialize>();
}
static std::shared_ptr<State> createReadyState() {
return std::make_shared<Ready>();
}
};
// 设备驱动类
class DeviceDriver {
public:
DeviceDriver() : currentState(StateFactory::createUnpluggedState()) {}
void unplug() {
currentState->onUnplug(this);
}
void plugIn() {
currentState->onPlugIn(this);
}
void initialize() {
currentState->onInitialize(this);
}
void ready() {
currentState->onReady(this);
}
void setState(const std::shared_ptr<State>& state) {
currentState = state;
}
private:
std::shared_ptr<State> currentState;
};
// 具体状态:未插入
class Unplugged : public State {
public:
void onUnplug(DeviceDriver* driver) override {
std::cout << "Already unplugged." << std::endl;
}
void onPlugIn(DeviceDriver* driver) override {
std::cout << "Device plugged in." << std::endl;
driver->setState(StateFactory::createPlugInState());
}
void onInitialize(DeviceDriver* driver) override {
std::cout << "Cannot initialize. Device not plugged in." << std::endl;
}
void onReady(DeviceDriver* driver) override {
std::cout << "Cannot be ready. Device not plugged in." << std::endl;
}
};
// 具体状态:已插入
class PlugIn : public State {
public:
PlugIn() : strategy(std::make_unique<QuickInitialization>()) {}
void onUnplug(DeviceDriver* driver) override {
std::cout << "Device unplugged." << std::endl;
driver->setState(StateFactory::createUnpluggedState());
}
void onPlugIn(DeviceDriver* driver) override {
std::cout << "Already plugged in." << std::endl;
}
void onInitialize(DeviceDriver* driver) override {
std::cout << "Device initialized." << std::endl;
strategy->initialize();
driver->setState(StateFactory::createInitializeState());
}
void onReady(DeviceDriver* driver) override {
std::cout << "Cannot be ready. Device not initialized." << std::endl;
}
private:
std::unique_ptr<InitializationStrategy> strategy;
};
// 具体状态:已初始化
class Initialize : public State {
public:
void onUnplug(DeviceDriver* driver) override {
std::cout << "Device unplugged." << std::endl;
driver->setState(StateFactory::createUnpluggedState());
}
void onPlugIn(DeviceDriver* driver) override {
std::cout << "Already plugged in and initialized." << std::endl;
}
void onInitialize(DeviceDriver* driver) override {
std::cout << "Already initialized." << std::endl;
}
void onReady(DeviceDriver* driver) override {
std::cout << "Device is ready to use." << std::endl;
driver->setState(StateFactory::createReadyState());
}
};
// 具体状态:已准备好
class Ready : public State {
public:
void onUnplug(DeviceDriver* driver) override {
std::cout << "Device unplugged." << std::endl;
driver->setState(StateFactory::createUnpluggedState());
}
void onPlugIn(DeviceDriver* driver) override {
std::cout << "Device is already ready." << std::endl;
}
void onInitialize(DeviceDriver* driver) override {
std::cout << "Device is already initialized and ready." << std::endl;
}
void onReady(DeviceDriver* driver) override {
std::cout << "Device is already ready." << std::endl;
}
};
int main() {
DeviceDriver driver;
// 模拟设备插拔和状态转移
driver.plugIn();
driver.initialize();
driver.ready();
driver.unplug();
driver.plugIn();
driver.ready();
return 0;
}
代码说明
-
策略接口
InitializationStrategy
:- 定义了一个初始化策略接口,包含一个
initialize
方法。 - 具体策略类
QuickInitialization
和FullInitialization
实现了不同的初始化策略。
- 定义了一个初始化策略接口,包含一个
-
状态工厂类
StateFactory
:- 提供静态方法创建不同状态的实例。
-
具体状态类
PlugIn
:- 包含一个策略对象
strategy
,在onInitialize
方法中使用该策略进行初始化。
- 包含一个策略对象
-
主函数
main
:- 创建一个
DeviceDriver
对象,并模拟设备的插拔和状态转移过程。
- 创建一个
通过这种方式,状态模式与工厂模式和策略模式协同使用,使得代码更加灵活和可维护。