行为型——状态模式C++实现

状态是一种行为设计模式,让你能在一个对象的内部状态变化时改变其行为,使其看上去就像改变了自身所属的类一样。

状态模式的简单实现可以是基于条件语句的状态机,即switch case结构。但后期可能会造成臃肿。建议为对象的所有可能状态新建一个类,将所有状态的对应行为抽取到这些类中。

实例

Context.h

#ifndef CONTEXT_H_
#define CONTEXT_H_

#include <string>
#include <memory>

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_

Context.cpp

#include "Context.h"

#include "ConcreteState.h"
#include <string>

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);
}

ForumAccount内包含一个状态AbstractState,ForumAccount执行具体命令时实际上是AbstractState执行具体命令,而AbstractState是基类,会根据积分在PrimaryState、MiddleState和HighState之间切换。因为AbstractState要切换状态,所以AbstractState要包含ForumAccount对象,切换状态时是ForumAccount对象set_state。

State.h

#ifndef STATE_H_
#define STATE_H_

#include <string>
#include <cstdio>
#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_

包含对象ForumAccount,积分变换可能会触发其set_state改变状态。 

ConcreteState.h

#ifndef CONCRETE_STATE_H_
#define CONCRETE_STATE_H_

#include <cstdio>
#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_

ConcreteState.cpp

#include "ConcreteState.h"

#include <memory>

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<MiddleState>(this));
    }
}

main.cpp

#include "Context.h"

int main() {
    // 注册新用户
    ForumAccount account("TOMOCAT");
    account.writeNote(20);
    account.downloadFile(20);
    account.replyNote(100);
    account.writeNote(40);
    account.downloadFile(80);
    account.writeNote(1000);
    account.downloadFile(80);
    return 0;
}

编译运行:

$g++ -g main.cpp Context.cpp ConcreteState.cpp -o state -std=c++11
$./state 
账号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, 当前级别为专家。

猜你喜欢

转载自blog.csdn.net/weixin_36389889/article/details/130970290
今日推荐