C++ 设计模式-状态模式

设计模式介绍

一、状态模式

1. 状态模式定义

允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。

2. 状态模式本质

根据状态来分离和选择行为

3. 状态模式结构和说明

(1) 结构

在这里插入图片描述

(2) 调用顺序

由上下文统一进行状态维护:
由上下文统一进行状态维护
由状态对象来维护和转换状态:
在这里插入图片描述

4. 状态模式适用情况

  1. 如果一个对象的行为取决于它的状态,而且它必须在运行时刻根据状态来改变它的行为,可以使用状态模式,来把状态和行为分离开。虽然分离开了,但状态和行为是有对应关系的,可以在运行期间,通过改变状态,就能够调用到该状态对应的状态处理对象上去,从而改变对象的行为。
  2. 如果一个操作中含有庞大的多分支语句,而且这些分支依赖于该对象的状态,可以使用状态模式,把各个分支的处理分散包装到单独的对象处理类中,这样,这些分支对应的对象就可以不依赖于其他对象而独立变化了。

5. 状态模式优缺点

(1) 优点
  1. 简化应用逻辑控制
    状态模式使用单独的类来封装一个状态的处理。如果把一个大的程序控制分成很多小块,每块定义一个状态来代表,那么就可以把这些逻辑控制的代码分散到很多单独的状态类中去,这样就把着眼点从执行状态提高到整个对象的状态,使得代码结构化和意图更清晰,从而简化应用的逻辑控制。

  2. 更好地分离状态和行为
    状态模式通过设置所有状态类的公共接口,把状态和状态对应的行为分离开,把所有与一个特定的状态相关的行为都放入一个对象中,使得应用程序在控制的时候,只需要关心状态的切换,而不用关心这个状态对应的真正处理

  3. 显式化进行状态转换
    状态模式为不同的状态引入独立的对象,使得状态的转换变得更加明确。而且状态对象可以保证上下文不会发生内部状态不一致的情况,因为上下文中只有一个变量来记录状态对象,只要为这一个变量赋值就可以了。

(2) 缺点

一个状态对应一个状态处理类,会使得程序引入太多的状态类,这样程序变得杂乱。

6. 相关模式

  1. 状态模式和策略模式
    这两个模式从模式结构上看是一样的,但是实现的功能却是不一样的。
    状态模式是根据状态的变化来选择相应的行为,不同的状态对应不同的类,每个状态对应的类实现了该状态对应的功能,在实现功能的同时,还会维护状态数据的变化。这些实现状态对应的功能的类之间是不能相互替换的。策略模式是根据需要或者是客户端的要求来选择相应的实现类,各个实现类是平等的,是可以相互替换的。另外策略模式可以让客户端来选择需要使用的策略算法;而状态模式一般是由上下文,或者是在状态实现类里面来维护具体的状态数据,通常不由客户端来指定状态。
  2. 状态模式和观察者模式
    这两个模式乍一看,功能是很相似的,但是又有区别,可以组合使用。
    这两个模式都是在状态发生改变的时候触发行为,只不过观察者模式的行为是固定的,那就是通知所有的观察者:而状态模式是根据状态来选择不同的处理。
    从表面来看,两个模式功能相似,观察者模式中的被观察对象就好比状态模式中的上下文,观察者模式中当被观察对象的状态发生改变的时候,触发的通知所有观察者的方法就好比是状态模式中,根据状态的变化选择对应的状态处理。
    但实际这两个模式是不同的,观察者模式的目的是在被观察者的状态发生改变的时候,触发观察者联动,具体如何处理观察者模式不管:而状态模式的主要目的在于根据状态来分离和选择行为,当状态发生改变的时候,动态地改变行为。
    这两个模式是可以组合使用的,比如在观察者模式的观察者部分,当被观察对象的状态发生了改变,触发通知了所有的观察者以后,观察者该怎么处理呢?这个时候就可以使用状态模式,根据通知过来的状态选择相应的处理。
  3. 状态模式和单例模式
    这两个模式可以组合使用,可以把状态模式中的状态处理类实现成单例。
  4. 状态模式和享元模式
    这两个模式可以组合使用。
    由于状态模式把状态对应的行为分散到多个状态对象中,会造成很多细粒度的状态对象,可以把这些状态处理对象通过享元模式来共享,从而节省资源。

状态模式示例代码

#include <iostream>
#include <string>
#include <memory>
#include <map>

using namespace std;

//由上下文统一进行状态维护

//投票上层接口
class VoteState
{
public:
    //user:投票人
    //VoteItem:投票项
    //voteInfo:本来这里应该传VoteManage对象,但是C++没有反射,只能暂时这样
    virtual void Vote(const std::string& user, const std::string& voteItem, std::map<std::string, std::string>& voteInfo) = 0;
};

//正常投票
class NormalVote : public VoteState
{
public:
    void Vote(const std::string& user, const std::string& voteItem, std::map<std::string, std::string>& voteInfo) override
    {
        voteInfo.emplace(user, voteItem);
        std::cout<<user<<":"<<voteItem<<":正常投票!"<<std::endl;
    }
};

//重复投票
class RepeatedVote : public VoteState
{
public:
    void Vote(const std::string& user, const std::string& voteItem, std::map<std::string, std::string>& voteInfo) override
    {
        std::cout<<user<<":"<<voteItem<<":重复投票!"<<std::endl;
    }
};

//投票管理器
class VoteManage
{
public:
    void Vote(const std::string& user, const std::string& voteItem)
    {
        std::unique_ptr<VoteState> pState(nullptr);
        const auto& iter = voteInfo.find(user);
        if(iter != voteInfo.end())
        {
            //重复投票
            pState.reset(new RepeatedVote());
        } else
        {
            //正常投票
            pState.reset(new NormalVote());
        }
        if(pState != nullptr)
        {
            pState->Vote(user, voteItem, voteInfo);
        }
    }

private:
    std::map<std::string, std::string> voteInfo; //投票信息 <投票人,投票项>
};


int main()
{
    VoteManage voteManage;
    for(uint32_t i = 0; i < 2; i++)
    {
        voteManage.Vote("张三","班长");
    }
    return 0;
}

#include <iostream>
#include <string>
#include <memory>
#include <map>

using namespace std;

//由状态对象来维护和转换状态

//投票上层接口
class VoteState
{
public:
    //user:投票人
    //VoteItem:投票项
    //voteInfo:本来这里应该传VoteManage对象,但是C++没有反射,只能暂时这样
    //voteState:同上
    virtual void Vote(const std::string& user, const std::string& voteItem, std::map<std::string, std::string>& voteInfo, std::map<std::string, std::shared_ptr<VoteState>>& voteState) = 0;
};

//重复投票
class RepeatedVote : public VoteState
{
public:
    void Vote(const std::string& user, const std::string& voteItem, std::map<std::string, std::string>& voteInfo,  std::map<std::string, std::shared_ptr<VoteState>>& voteState) override
    {
        std::cout<<user<<":"<<voteItem<<":重复投票!"<<std::endl;
    }
};

//正常投票
class NormalVote : public VoteState
{
public:
    void Vote(const std::string& user, const std::string& voteItem, std::map<std::string, std::string>& voteInfo, std::map<std::string, std::shared_ptr<VoteState>>& voteState) override
    {
        voteInfo.emplace(user, voteItem);
        voteState[user].reset(new RepeatedVote());
        std::cout<<user<<":"<<voteItem<<":正常投票!"<<std::endl;
    }
};

//投票管理器
class VoteManage
{
public:
    void Vote(const std::string& user, const std::string& voteItem)
    {
        std::shared_ptr<VoteState> pState(nullptr);
        const auto& iter = voteState.find(user);
        if(iter == voteState.end())
        {
            auto ret = voteState.emplace(user, new NormalVote());
            if(ret.second)
            {
                pState = ret.first->second;
            }
        } else
        {
            pState = iter->second;
        }

        if(pState != nullptr)
        {
            pState->Vote(user, voteItem, voteInfo, voteState);
        }
    }

private:
    std::map<std::string, std::string> voteInfo; //投票信息 <投票人,投票项>
    std::map<std::string, std::shared_ptr<VoteState>> voteState; //投票状态 <投票人, 投票状态>
};


int main()
{
    VoteManage voteManage;
    for(uint32_t i = 0; i < 3; i++)
    {
        voteManage.Vote("张三","班长");
    }
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值