• 17 C++设计模式之状态(State)模式


    状态(State)模式定义

    状态模式(state),当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。

    状态(State)模式优缺点

    优点
    • 将与特定状态相关的行为局部化,并且将不同状态的行为分割开来。
    • 将特定的状态相关的行为都放入一个对象中,由于所有与状态相关的代码都存在于某个 ConcreteState中,所以通过定义新的子类可以很容易的增加新的状态和转换。
    • 消除庞大的条件分支语句。
    • 状态模式通过把各种状态转移逻辑分布到state的子类之间,来减少相互之间的依赖
    缺点
    • 如果状态机只有很少的几个状态,或者很少发生改变,那么应用该模式可能会显得小题大作

    状态(State)模式构成与实现

    构成
    • 上下文(Context)保存了对于一个具体状态对象的引用,并会将所有与该状态相关的工作委派给它。上下文通过状态接口与状态对象交互,且会提供一个设置器用于传递新的状态对象。
    • 状态(State)接口会声明特定于状态的方法。这些方法应能被其他所有具体状态所理解,因为你不希望某些状态所拥有的方法永远不会被调用。
    • 具体状态(Concrete States)会自行实现特定于状态的方法。为了避免多个状态中包含相似代码,你可以提供一个封装有部分通用行为的中间抽象类。状态对象可存储对于上下文对象的反向引用。状态可以通过
      该引用从上下文处获取所需信息,并且能触发状态转移。
    • 上下文和具体状态都可以设置上下文的下个状态,并可通过替换连接到上下文的状态对象来完成实际的状态转换。
    实例

    Context.h:

    #ifndef CONTEXT_H_
    #define CONTEXT_H_
    
    #include 
    #include 
    
    class AbstractState;
    
    // 论坛账号
    class ForumAccount {
     public:
        explicit ForumAccount(std::string name);
        void set_state(std::shared_ptr<AbstractState> state) {
            state_ = state;
        }
        std::shared_ptr<AbstractState> get_state() {
            return state_;
        }
        std::string get_name() {
            return name_;
        }
        void downloadFile(int score);
        void writeNote(int score);
        void replyNote(int score);
    
     private:
        std::shared_ptr<AbstractState> state_;
        std::string name_;
    };
    
    #endif  // CONTEXT_H_
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    State.h:

    #ifndef STATE_H_
    #define STATE_H_
    
    #include 
    #include 
    #include "Context.h"
    
    class AbstractState {
     public:
        virtual void checkState() = 0;
    
        void set_point(int point) {
            point_ = point;
        }
        int get_point() {
            return point_;
        }
        void set_state_name(std::string name) {
            state_name_ = name;
        }
        std::string get_state_name() {
            return state_name_;
        }
        ForumAccount* get_account() {
            return account_;
        }
    
        virtual void downloadFile(int score) {
            printf("%s下载文件, 扣除%d积分。\n", account_->get_name().c_str(), score);
            point_ -= score;
            checkState();
            printf("%s剩余积分为%d, 当前级别为%s。\n", account_->get_name().c_str(), point_, account_->get_state()->get_state_name().c_str());
        }
    
        virtual void writeNote(int score) {
            printf("%s发布留言, 增加%d积分。\n", account_->get_name().c_str(), score);
            point_ += score;
            checkState();
            printf("%s剩余积分为%d, 当前级别为%s。\n", account_->get_name().c_str(), point_, account_->get_state()->get_state_name().c_str());
        }
    
        virtual void replyNote(int score) {
            printf("%s回复留言, 增加%d积分。\n", account_->get_name().c_str(), score);
            point_ += score;
            checkState();
            printf("%s剩余积分为%d, 当前级别为%s。\n", account_->get_name().c_str(), point_, account_->get_state()->get_state_name().c_str());
        }
    
     protected:
        ForumAccount* account_;
        int point_;
        std::string state_name_;
    };
    
    #endif  // STATE_H_
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    ConcreteState.h:

    #ifndef CONCRETE_STATE_H_
    #define CONCRETE_STATE_H_
    
    #include 
    #include "State.h"
    
    // 具体状态类: 新手
    class PrimaryState : public AbstractState {
     public:
        explicit PrimaryState(AbstractState* state) {
            account_ = state->get_account();
            point_ = state->get_point();
            state_name_ = "新手";
        }
        explicit PrimaryState(ForumAccount *account) {
            account_ = account;
            point_ = 0;
            state_name_ = "新手";
        }
        void downloadFile(int score) override {
            printf("对不起, %s没有下载文件的权限!\n", account_->get_name().c_str());
        }
        void checkState() override;
    };
    
    // 具体状态类: 高手
    class MiddleState : public AbstractState {
     public:
        explicit MiddleState(AbstractState* state) {
            account_ = state->get_account();
            point_ = state->get_point();
            state_name_ = "高手";
        }
    
        void writeNote(int score) override {
            printf("%s发布留言, 增加%d积分。\n", account_->get_name().c_str(), score * 2);
            point_ += score * 2;
            checkState();
            printf("%s剩余积分为%d, 当前级别为%s。\n", account_->get_name().c_str(), point_, account_->get_state()->get_state_name().c_str());
        }
        void checkState() override;
    };
    
    // 具体状态类: 专家
    class HighState : public AbstractState {
     public:
        explicit HighState(AbstractState* state) {
            account_ = state->get_account();
            point_ = state->get_point();
            state_name_ = "专家";
        }
    
        void writeNote(int score) override {
            printf("%s发布留言, 增加%d积分。\n", account_->get_name().c_str(), score * 2);
            point_ += score * 2;
            checkState();
            printf("%s剩余积分为%d, 当前级别为%s。\n", account_->get_name().c_str(), point_, account_->get_state()->get_state_name().c_str());
        }
    
        virtual void downloadFile(int score) {
            printf("%s下载文件, 扣除%d积分。\n", account_->get_name().c_str(), score / 2);
            point_ -= score / 2;
            checkState();
            printf("%s剩余积分为%d, 当前级别为%s。\n", account_->get_name().c_str(), point_, account_->get_state()->get_state_name().c_str());
        }
    
        void checkState() override;
    };
    
    #endif  // CONCRETE_STATE_H_
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70

    ConcreteState.cpp:

    #include "ConcreteState.h"
    
    #include 
    
    void PrimaryState::checkState() {
        if (point_ >= 1000) {
            account_->set_state(std::make_shared<HighState>(this));
        } else if (point_ >= 100) {
            account_->set_state(std::make_shared<MiddleState>(this));
        }
    }
    
    void MiddleState::checkState() {
        if (point_ >= 1000) {
            account_->set_state(std::make_shared<HighState>(this));
        } else if (point_ < 100) {
            account_->set_state(std::make_shared<PrimaryState>(this));
        }
    }
    
    void HighState::checkState() {
        if (point_ < 100) {
            account_->set_state(std::make_shared<PrimaryState>(this));
        } else if (point_ < 1000) {
            account_->set_state(std::make_shared<HighState>(this));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    Context.cpp:

    #include "Context.h"
    
    #include "ConcreteState.h"
    #include 
    
    ForumAccount::ForumAccount(std::string name)
        : name_(name), state_(std::make_shared<PrimaryState>(this)) {
        printf("账号%s注册成功!\n", name.c_str());
    }
    
    void ForumAccount::downloadFile(int score) {
        state_->downloadFile(score);
    }
    
    void ForumAccount::writeNote(int score) {
        state_->writeNote(score);
    }
    
    void ForumAccount::replyNote(int score) {
        state_->replyNote(score);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    main.cpp:

    #include "Context.h"
    
    int main() {
    
        system("chcp 65001");
        // 注册新用户
        ForumAccount account("TOMOCAT");
        account.writeNote(20);
        account.downloadFile(20);
        account.replyNote(100);
        account.writeNote(40);
        account.downloadFile(80);
        account.writeNote(1000);
        account.downloadFile(80);
        system("pause");
        return 0;
        
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    输出:

    Active code page: 65001
    账号TOMOCAT注册成功!
    TOMOCAT发布留言, 增加20积分。
    TOMOCAT剩余积分为20, 当前级别为新手。
    对不起, TOMOCAT没有下载文件的权限!
    TOMOCAT回复留言, 增加100积分。
    TOMOCAT剩余积分为120, 当前级别为高手。
    TOMOCAT发布留言, 增加80积分。
    TOMOCAT剩余积分为200, 当前级别为高手。
    TOMOCAT下载文件, 扣除80积分。
    TOMOCAT剩余积分为120, 当前级别为高手。
    TOMOCAT发布留言, 增加2000积分。
    TOMOCAT剩余积分为2120, 当前级别为专家。
    TOMOCAT下载文件, 扣除40积分。
    TOMOCAT剩余积分为2080, 当前级别为专家。
    Press any key to continue . . .
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
  • 相关阅读:
    Logistic回归——银行违约情况分析
    Gmail 将停止支持基本 HTML 视图
    zabbix 7.0编译部署教程
    阿里云国际站:阿里云linux扩充磁盘大小常见问题
    JavaScript-三大结构
    数仓面经大框架
    淘宝API详情接口调用示例
    Vue|单文件组件与脚手架安装
    java计算机毕业设计销售人员绩效管理系统源程序+mysql+系统+lw文档+远程调试
    长时间预测模型DLiner、NLiner模型(论文解读)
  • 原文地址:https://blog.csdn.net/qq_45531502/article/details/126419284