狀態模式建議為對象的所有可能狀態新建一個類, 然后將所有狀態的對應行為抽取到這些類中。
原始對象被稱為上下文 (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;
}