• 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
  • 相关阅读:
    【JUC】Java并发编程从挖坑到入土全解(2)
    汇量科技app手游出海白皮书:全球买量与变现指南
    N皇后问题(分支限界法)
    【考研英语语法】祈使句
    网工记背命令(7)----静态路由(负载分担,主备备份)
    网安学习-CTF夺旗
    【Ubuntu】树莓派4B安装Ubuntu18.04(超详细)
    Android Aidl跨进程通讯(四)--接口回调,服务端向客户端发送数据
    初中三年回忆录
    gRpc入门
  • 原文地址:https://blog.csdn.net/qq_45531502/article/details/126419284