概念
處理對象的狀態變化是軟件開發中一個重要的課題,尤其是在設計過程中,如何有效管理對象的狀態變化對于軟件的可維護性、可擴展性和整體設計都至關重要。
狀態模式
狀態模式通過將狀態封裝為對象,允許對象在內部狀態改變時改變其行為。狀態模式使得狀態的切換變得靈活,減少了條件語句的使用。
#include <iostream>
#include <memory> // 前向聲明
class Context; // 抽象狀態類
class State {
public: virtual void handle(Context& context) = 0; virtual ~State() = default;
}; // 上下文類
class Context {
private: std::unique_ptr<State> state; public: Context(std::unique_ptr<State> initialState) : state(std::move(initialState)) {} void setState(std::unique_ptr<State> newState) { state = std::move(newState); } void request() { state->handle(*this); // 使用當前狀態進行處理 }
}; // 具體狀態類 A
class ConcreteStateA : public State {
public: void handle(Context& context) override { std::cout << "Handling state A. Transitioning to state B." << std::endl; context.setState(std::make_unique<ConcreteStateB>()); // 轉換狀態 }
}; // 具體狀態類 B
class ConcreteStateB : public State {
public: void handle(Context& context) override { std::cout << "Handling state B. Transitioning to state A." << std::endl; context.setState(std::make_unique<ConcreteStateA>()); // 轉換狀態 }
}; int main() { Context context(std::make_unique<ConcreteStateA>()); context.request(); // 當前是狀態 A context.request(); // 當前是狀態 B context.request(); // 當前是狀態 A context.request(); // 當前是狀態 B return 0;
}
代碼解析
- 狀態基類:定義了處理方法的接口,子類需要實現具體行為。
- 具體狀態類:分別實現不同狀態的行為,并在處理過程中改變上下文的狀態。
- 上下文類:持有一個狀態對象,通過調用當前狀態的 handle 方法來響應請求,并允許狀態的轉換。
觀察者模式
觀察者模式用于建立一種一對多的依賴關系,當被觀察者的狀態改變時,所有依賴于它的觀察者都會收到通知。適用于需要通知多個對象狀態變化的場景。
#include <iostream>
#include <vector>
#include <memory> // 抽象觀察者類
class Observer {
public: virtual void update() = 0; virtual ~Observer() = default;
}; // 抽象被觀察者類
class Subject {
public: virtual void attach(std::shared_ptr<Observer> observer) = 0; virtual void detach(std::shared_ptr<Observer> observer) = 0; virtual void notify() = 0; virtual ~Subject() = default;
}; // 具體被觀察者
class ConcreteSubject : public Subject {
private: std::vector<std::shared_ptr<Observer>> observers; int state; public: void setState(int newState) { state = newState; notify(); } int getState() const { return state; } void attach(std::shared_ptr<Observer> observer) override { observers.push_back(observer); } void detach(std::shared_ptr<Observer> observer) override { // 在這里可以實現 detach 邏輯 } void notify() override { for (const auto& observer : observers) { observer->update(); // 通知所有觀察者 } }
}; // 具體觀察者
class ConcreteObserver : public Observer {
private: ConcreteSubject& subject; public: ConcreteObserver(ConcreteSubject& subject) : subject(subject) {} void update() override { std::cout << "Observer updated: New state = " << subject.getState() << std::endl; }
}; int main() { ConcreteSubject subject; auto observer1 = std::make_shared<ConcreteObserver>(subject); subject.attach(observer1); // 注冊觀察者 subject.setState(1); // 改變狀態,通知觀察者 subject.setState(2); // 再改變狀態,通知觀察者 return 0;
}
代碼解析
- 觀察者接口:定義了一個更新方法,所有具體觀察者都需實現該方法。
- 被觀察者接口:定義附加、解除和通知觀察者的方法。
- 具體被觀察者:持有觀察者的列表,維護自己的狀態,并在狀態變化時通知觀察者。
- 具體觀察者:在狀態變化時采取相應的行動。
狀態機模式
狀態機模式通常用于表示有限狀態機的行為,適用于狀態變化明確且數量有限的場景。狀態機可以維護狀態轉移的規則和條件。
#include <iostream>
#include <map>
#include <functional> // 狀態機類
class StateMachine {
public: using State = std::string; using Transition = std::function<void()>; private: State currentState; std::map<State, std::map<State, Transition>> transitions; public: void addTransition(State from, State to, Transition transition) { transitions[from][to] = transition; // 記錄狀態轉移 } void setState(State state) { currentState = state; // 設置當前狀態 } void transition(State to) { if (transitions[currentState].count(to)) { transitions[currentState][to](); // 執行轉移邏輯 currentState = to; // 更新當前狀態 } else { std::cout << "Invalid transition from " << currentState << " to " << to << std::endl; } } State getCurrentState() const { return currentState; // 獲取當前狀態 }
}; int main() { StateMachine sm; // 添加狀態轉移 sm.addTransition("Idle", "Working", []() { std::cout << "Transitioning from Idle to Working." << std::endl; }); sm.addTransition("Working", "Idle", []() { std::cout << "Transitioning from Working to Idle." << std::endl; }); sm.setState("Idle"); sm.transition("Working"); // 有效轉移 sm.transition("Idle"); // 有效轉移 sm.transition("Working"); // 有效轉移 sm.transition("Idle"); // 有效轉移 return 0;
}
代碼解析
- 狀態機類:管理當前狀態和狀態轉移邏輯。
- 狀態轉移:通過方法 transition 來執行狀態之間的切換,檢查是否允許轉移,并執行轉移后的邏輯。
使用監聽器模式
在某些情況下,可以通過事件的方式來處理狀態變化,使用事件監聽器來觀察和處理狀態變化。
#include <iostream>
#include <vector>
#include <string> // 監聽器接口
class Listener {
public: virtual void onStateChanged(const std::string& newState) = 0; virtual ~Listener() = default;
}; // 主類,它的狀態會變化
class StateTracker {
private: std::string state; std::vector<Listener*> listeners; public: void addListener(Listener* listener) { listeners.push_back(listener); } void changeState(const std::string& newState) { state = newState; notifyListeners(); } void notifyListeners() { for (auto listener : listeners) { listener->onStateChanged(state); // 通知所有監聽者 } }
}; // 具體監聽者
class ConcreteListener : public Listener {
public: void onStateChanged(const std::string& newState) override { std::cout << "State changed to: " << newState << std::endl; }
}; int main() { StateTracker tracker; ConcreteListener listener; tracker.addListener(&listener); // 添加監聽者 tracker.changeState("Active"); // 改變狀態,觸發通知 tracker.changeState("Inactive"); // 再改變狀態,觸發通知 return 0;
}
代碼解析
- 監聽器接口:定義了狀態變化的響應方法。
- 主類:持有狀態并維護監聽者列表,狀態變化時通知所有監聽者。
- 具體監聽者:實現狀態變化時的處理邏輯。
總結
處理對象的狀態變化通常可以通過幾種設計模式和技術來實現,選擇適當的方法取決于項目需求和復雜性。這些方法包括:
- 狀態模式:將不同狀態封裝為對象,負責相應的行為。
- 觀察者模式:允許多個觀察者監視狀態的變化,并在狀態變化時得到通知。
- 狀態機模式:清晰地管理狀態和狀態之間的轉移邏輯。
- 監聽器模式:以事件驅動的方式處理狀態變化。