状态模式建议为对象的所有可能状态新建一个类, 然后将所有状态的对应行为抽取到这些类中。
原始对象被称为上下文 (context), 它并不会自行实现所有行为, 而是会保存一个指向表示当前状态的状态对象的引用, 且将所有与状态相关的工作委派给该对象。如需将上下文转换为另外一种状态, 则需将当前活动的状态对象替换为另外一个代表新状态的对象。 采用这种方式是有前提的: 所有状态类都必须遵循同样的接口, 而且上下文必须仅通过接口与这些对象进行交互。
+-------------------+
| Context |
+-------------------+
| - currentState |
| + setState() |
| + userInput() |
+-------------------+
▲
│
+--------│---------------------------------------------+
│ ▼ │
│ +----------------+ │
│ | State | <abstract> │
│ +----------------+ │
│ | + enter() | │
│ | + handleInput()| <pure virtual> │
│ +----------------+ │
│ │
│ ▲ ▲ ▲ ▲ │
│ │ │ │ │ │
│ +-----------+ +------------+ +-----------+ +----------------+
│ | NotLoggedIn | | InputPassword | | LoggingIn | | LoggedIn | ...
│ +-----------+ +------------+ +-----------+ +----------------+
#include <iostream>
#include <string>
class LoginContext; // 前向声明
// 抽象状态类
class LoginState {
public:
virtual ~LoginState() = default;
virtual void enter(LoginContext* context) = 0; // 进入状态时的行为
virtual void handleInput(LoginContext* context, const std::string& input) = 0; // 处理输入
};
// 前向声明所有具体状态类
class NotLoggedInState;
class InputtingPasswordState;
class LoggingInState;
class LoggedInState;
class LoginFailedState;
// 上下文类
class LoginContext {
private:
LoginState* currentState;
std::string username;
std::string password;
public:
LoginContext() : currentState(nullptr) {}
~LoginContext() {
delete currentState; // 释放状态资源
}
void setState(LoginState* state) {
if (currentState != nullptr) {
delete currentState; // 释放旧状态资源
}
currentState = state;
if (currentState != nullptr) {
currentState->enter(this); // 自动触发进入逻辑
}
}
void userInput(const std::string& input) {
if (currentState != nullptr) {
currentState->handleInput(this, input);
}
}
const std::string& getUsername() const { return username; }
void setUsername(const std::string& name) { username = name; }
const std::string& getPassword() const { return password; }
void setPassword(const std::string& pwd) { password = pwd; }
};
// 具体状态类定义
class NotLoggedInState : public LoginState {
public:
void enter(LoginContext* context) override {
std::cout << "进入未登录状态,请输入用户名和密码。\n";
}
void handleInput(LoginContext* context, const std::string& input) override;
};
class InputtingPasswordState : public LoginState {
public:
void enter(LoginContext* context) override {
std::cout << "请输入密码:\n";
}
void handleInput(LoginContext* context, const std::string& input) override;
};
class LoggingInState : public LoginState {
public:
void enter(LoginContext* context) override;
void handleInput(LoginContext* /*context*/, const std::string& /*input*/) override {}
};
class LoggedInState : public LoginState {
public:
void enter(LoginContext* context) override {
std::cout << "[状态] 登录成功!欢迎回来。" << std::endl;
}
void handleInput(LoginContext* /*context*/, const std::string& /*input*/) override {}
};
class LoginFailedState : public LoginState {
public:
void enter(LoginContext* context) override {
std::cout << "[状态] 登录失败,请重新输入用户名。" << std::endl;
context->setState(new NotLoggedInState());
}
void handleInput(LoginContext* /*context*/, const std::string& /*input*/) override {}
};
// 状态类成员函数实现(解决循环依赖)
void NotLoggedInState::handleInput(LoginContext* context, const std::string& input) {
std::cout << "请输入用户名:" << std::endl;
context->setUsername(input);
context->setState(new InputtingPasswordState());
}
void InputtingPasswordState::handleInput(LoginContext* context, const std::string& input) {
context->setPassword(input);
std::cout << "正在登陆...\n";
context->setState(new LoggingInState());
}
void LoggingInState::enter(LoginContext* context) {
std::cout << "[状态] 当前状态:登录中" << std::endl;
// 模拟登录验证
const std::string user = context->getUsername();
const std::string pass = context->getPassword();
if (user == "admin" && pass == "123456") {
context->setState(new LoggedInState());
}
else {
context->setState(new LoginFailedState());
}
}
//int main() {
// LoginContext context;
// context.setState(new NotLoggedInState());
//
// // 模拟用户输入流程
// context.userInput("admin"); // 输入用户名
// context.userInput("wrongpass"); // 输入错误密码
// context.userInput("admin"); // 再次输入用户名
// context.userInput("123456"); // 输入正确密码
//
// return 0;
//}
int main() {
LoginContext context;
context.setState(new NotLoggedInState());
std::string input;
while (true) {
std::cout << "> ";
std::getline(std::cin, input);
if (input == "exit") break;
context.userInput(input);
}
return 0;
}