State(状态模式)行为型

一、概述

描述:一天有早中晚,不同时间下,太阳光是不一样的。所以随着早中晚的状态变化,太阳的行为也随着变化。

定义:状态模式是一种行为设计模式, 让你能在一个对象的内部状态变化时改变其行为, 使其看上去就像改变了自身所属的类一样。这其实就有点类似算法中的有限状态机的形式。

其主要思想是程序在任意时刻仅可处于几种有限的状态中。 在任何一个特定状态中, 程序的行为都不相同, 且可瞬间从一个状态切换到另一个状态。 不过, 根据当前状态, 程序可能会切换到另外一种状态, 也可能会保持当前状态不变。 这些数量有限且预先定义的状态切换规则被称为转移。

二、结构

在这里插入图片描述

  1. 上下文(Context)保存了对于一个具体状态对象的引用,并会将所有与该状态相关的工作委派给它。上下文通过状态接口与状态对象交互,且会提供一个设置器用于传递新的状态对象。

  2. 状态(State)接口会声明特定于状态的方法。这些方法应能被其他所有具体状态所理解,因为你不希望某些状态所拥有的方法永远不会被调用。

  3. 具体状态(Concrete States)会自行实现特定于状态的方法。为了避免多个状态中包含相似代码,你可以提供一个封装有部分通用行为的中间抽象类。状态对象可存储对于上下文对象的反向引用。状态可以通过该引用从上下文处获取所需信息,并且能触发状态转移。

  4. 上下文和具体状态都可以设置上下文的下个状态,并可通过替换连接到上下文的状态对象来完成实际的状态转换。

三、实例

#include<iostream>
#include<string>
#include<cstdio>
#include<memory>
using namespace std;

class AbstractState;

// 论坛账号
class ForumAccount {
private:
    shared_ptr<AbstractState> state_;
    string name_;
public:
    explicit ForumAccount(string name);
    void set_state(shared_ptr<AbstractState> state) {
        state_ = state;
    }
    shared_ptr<AbstractState> get_state() {
        return state_;
    }
    string get_name() {
        return name_;
    }
    void downloadFile(int score);
    void writeNote(int score);
    void replyNote(int score);

};



class AbstractState {
protected:
    ForumAccount* account_;
    int point_;
    string state_name_;
public:
    virtual void checkState() = 0;

    void set_point(int point) {
        point_ = point;
    }
    int get_point() {
        return point_;
    }
    void set_state_name(string name) {
        state_name_ = name;
    }
    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());
    }
};



// 具体状态类: 新手
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;
};


void PrimaryState::checkState() {
    if (point_ >= 1000) {
        account_->set_state(make_shared<HighState>(this));
    }
    else if (point_ >= 100) {
        account_->set_state(make_shared<MiddleState>(this));
    }
}

void MiddleState::checkState() {
    if (point_ >= 1000) {
        account_->set_state(make_shared<HighState>(this));
    }
    else if (point_ < 100) {
        account_->set_state(make_shared<PrimaryState>(this));
    }
}

void HighState::checkState() {
    if (point_ < 100) {
        account_->set_state(make_shared<PrimaryState>(this));
    }
    else if (point_ < 1000) {
        account_->set_state(make_shared<HighState>(this));
    }
}


ForumAccount::ForumAccount(std::string name)
    : name_(name), state_(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);
}


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

在这里插入图片描述

四、适用场景

  1. 对象需要根据自身当前状态进行不同行为,同时状态的数量非常多且与状态相关的代码会频繁变更的话,可使用状态模式。
  2. 某个类需要根据成员变量的当前值改变自身行为,从而需要使用大量的条件语句时,可使用该模式。
  3. 当相似状态和基于条件的状态机转换中存在许多重复代码时,可使用状态模式。

五、优缺点

优点:

  1. 单一职责原则。将与特定状态相关的代码放在单独的类中。
  2. 开闭原则。无需修改已有状态类和上下文就能引入新状态。
  3. 通过消除臃肿的状态机条件语句简化上下文代码。

缺点:

  1. 如果状态机只有很少的几个状态,或者很少发生改变,那么应用该模式可能会显得小题大作。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值