设计模式介绍
一、状态模式
1. 状态模式定义
允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。
2. 状态模式本质
根据状态来分离和选择行为
3. 状态模式结构和说明
(1) 结构
(2) 调用顺序
由上下文统一进行状态维护:
由状态对象来维护和转换状态:
4. 状态模式适用情况
- 如果一个对象的行为取决于它的状态,而且它必须在运行时刻根据状态来改变它的行为,可以使用状态模式,来把状态和行为分离开。虽然分离开了,但状态和行为是有对应关系的,可以在运行期间,通过改变状态,就能够调用到该状态对应的状态处理对象上去,从而改变对象的行为。
- 如果一个操作中含有庞大的多分支语句,而且这些分支依赖于该对象的状态,可以使用状态模式,把各个分支的处理分散包装到单独的对象处理类中,这样,这些分支对应的对象就可以不依赖于其他对象而独立变化了。
5. 状态模式优缺点
(1) 优点
-
简化应用逻辑控制
状态模式使用单独的类来封装一个状态的处理。如果把一个大的程序控制分成很多小块,每块定义一个状态来代表,那么就可以把这些逻辑控制的代码分散到很多单独的状态类中去,这样就把着眼点从执行状态提高到整个对象的状态,使得代码结构化和意图更清晰,从而简化应用的逻辑控制。 -
更好地分离状态和行为
状态模式通过设置所有状态类的公共接口,把状态和状态对应的行为分离开,把所有与一个特定的状态相关的行为都放入一个对象中,使得应用程序在控制的时候,只需要关心状态的切换,而不用关心这个状态对应的真正处理 -
显式化进行状态转换
状态模式为不同的状态引入独立的对象,使得状态的转换变得更加明确。而且状态对象可以保证上下文不会发生内部状态不一致的情况,因为上下文中只有一个变量来记录状态对象,只要为这一个变量赋值就可以了。
(2) 缺点
一个状态对应一个状态处理类,会使得程序引入太多的状态类,这样程序变得杂乱。
6. 相关模式
- 状态模式和策略模式
这两个模式从模式结构上看是一样的,但是实现的功能却是不一样的。
状态模式是根据状态的变化来选择相应的行为,不同的状态对应不同的类,每个状态对应的类实现了该状态对应的功能,在实现功能的同时,还会维护状态数据的变化。这些实现状态对应的功能的类之间是不能相互替换的。策略模式是根据需要或者是客户端的要求来选择相应的实现类,各个实现类是平等的,是可以相互替换的。另外策略模式可以让客户端来选择需要使用的策略算法;而状态模式一般是由上下文,或者是在状态实现类里面来维护具体的状态数据,通常不由客户端来指定状态。 - 状态模式和观察者模式
这两个模式乍一看,功能是很相似的,但是又有区别,可以组合使用。
这两个模式都是在状态发生改变的时候触发行为,只不过观察者模式的行为是固定的,那就是通知所有的观察者:而状态模式是根据状态来选择不同的处理。
从表面来看,两个模式功能相似,观察者模式中的被观察对象就好比状态模式中的上下文,观察者模式中当被观察对象的状态发生改变的时候,触发的通知所有观察者的方法就好比是状态模式中,根据状态的变化选择对应的状态处理。
但实际这两个模式是不同的,观察者模式的目的是在被观察者的状态发生改变的时候,触发观察者联动,具体如何处理观察者模式不管:而状态模式的主要目的在于根据状态来分离和选择行为,当状态发生改变的时候,动态地改变行为。
这两个模式是可以组合使用的,比如在观察者模式的观察者部分,当被观察对象的状态发生了改变,触发通知了所有的观察者以后,观察者该怎么处理呢?这个时候就可以使用状态模式,根据通知过来的状态选择相应的处理。 - 状态模式和单例模式
这两个模式可以组合使用,可以把状态模式中的状态处理类实现成单例。 - 状态模式和享元模式
这两个模式可以组合使用。
由于状态模式把状态对应的行为分散到多个状态对象中,会造成很多细粒度的状态对象,可以把这些状态处理对象通过享元模式来共享,从而节省资源。
状态模式示例代码
#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;
}