设计模式(C++)-行为型模式-状态模式

设计模式(C++)-行为型模式-状态模式

一、状态模式概述

状态模式(State Pattern):是一种行为型设计模式,它允许一个对象在其内部状态改变时改变其行为,使得对象看起来似乎修改了其类。
核心思想:允许对象在内部状态发生改变时改变其行为,这个对象看起来就像是改变了它的类。

二、状态模式UML类图

状态模式场景

以抽奖活动为例。

有四个状态:

  • 【抽奖状态】
  • 【可以抽奖】
  • 【发放奖品】
  • 【奖品已领完】
    抽奖活动的初始状态为【不能抽奖】状态,在扣除50积分后进入【可以抽奖】状态,【可以抽奖】状态有90%的几率不中奖,
    不中奖就会回到【抽奖状态】,10%的几率中奖,中奖后进入【发放奖品】状态,当奖品数量为0是进入【奖品已领完】状态。
    如果用switch/if实现起来比较复杂下面用状态模式实现。

三、代码实现

cpp 复制代码
//state.h
#pragma once
/*
*状态模式
*每个人、事物在不同的状态下会有不同表现(动作),而一个状态又会在不同的表现下转移到下一个不同的状态(State)。
主要解决:
1.当状态数目不是很多的时候,Switch/Case 可能可以搞定。但是当状态数目很多的时候(实际系统中也正是如此),维护一大组
的Switch/Case 语句将是一件异常困难并且容易出错的事情。
2.状态逻辑和动作实现没有分离。在很多的系统实现中,动作的实现代码直接写在状态的逻辑当中。这带来的后果就是系统的扩展性
和维护得不到保证。
举例:以抽奖活动为例。
有四个状态:
- 【抽奖状态】
- 【可以抽奖】
- 【发放奖品】
- 【奖品已领完】
抽奖活动的初始状态为【不能抽奖】状态,在扣除50积分后进入【可以抽奖】状态,【可以抽奖】状态有90%的几率不中奖,
不中奖就会回到【抽奖状态】,10%的几率中奖,中奖后进入【发放奖品】状态,当奖品数量为0是进入【奖品已领完】状态。
如果用switch/if实现起来比较复杂下面用状态模式实现
*/
#include <iostream>
#include <time.h>
class State {
public:
	//扣除50积分
	virtual void deductMeney() = 0;

	//是否中奖
	virtual bool raffle() = 0;

	//发放奖品
	virtual void dispensePrize() = 0;
};
void testState();

//state.cc
#include "state.h"
#include "raffleactivity.h"
/*
优点:
1.封装了转换规则。
2.枚举可能的状态,在枚举状态之前需要确定状态种类。
3.将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。
4.允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块。
5.可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。
*/
void testState() {
	std::cout << "=================state start===============" << std::endl;
	RaffleActivity* activity = new RaffleActivity(1);
	for (int i = 0; i < 50; i++)
	{
		std::cout << "第" << i << "次抽奖" << std::endl;
		activity->deductMoney();
		activity->raffle();
		std::cout << std::endl;
	}
	std::cout << "=================state end===============" << std::endl;
}

//norafflestate.h
#pragma once
#include <iostream>
#include "state.h"
class RaffleActivity;
//不能抽奖状态
class NoRaffleState :public State {
public:
	NoRaffleState(RaffleActivity* activity);
	//在不能抽奖状态是可以扣积分的,扣除积分后设置成可以抽奖状态
	void deductMeney() override;
	bool raffle() override;
	void dispensePrize() override;
private:
	RaffleActivity* m_activity;
};

//norafflestate.cc
#include "norafflestate.h"
#include "raffleactivity.h"
NoRaffleState::NoRaffleState(RaffleActivity* activity) {
	m_activity = activity;
}
//在不能抽奖状态是可以扣积分的,扣除积分后设置成可以抽奖状态
void NoRaffleState::deductMeney(){
	std::cout << "扣除50积分,可以抽奖了" << std::endl;
	m_activity->setState(m_activity->getCanRaffleState());
}
bool NoRaffleState::raffle(){
	std::cout << "扣了积分才能抽奖" << std::endl;
	return false;
}
void NoRaffleState::dispensePrize(){
	std::cout << "不能发放奖品" << std::endl;
}
//dispensestate.h
#pragma once
#include <iostream>
#include "state.h"
class RaffleActivity;
//发放奖品状态
class DispenseState :public State {
public:
	DispenseState(RaffleActivity*activity);
	void deductMeney() override;
	bool raffle() override;
	//发放奖品
	void dispensePrize() override;
private:
	RaffleActivity* m_activity;
};
//dispensestate.cc
#include "dispensestate.h"
#include "raffleactivity.h"

DispenseState::DispenseState(RaffleActivity*activity) {
	m_activity = activity;
}
void DispenseState::deductMeney(){
	std::cout << "不能扣除积分" << std::endl;
}
bool DispenseState::raffle(){
	std::cout << "不能抽奖了" << std::endl;
	return false;
}
//发放奖品
void DispenseState::dispensePrize(){
	if (m_activity->getCount() > 0)
	{
		std::cout << "送出奖品" << std::endl;
		m_activity->setState(m_activity->getNoRaffleState());
	}
	else
	{
		std::cout << "很遗憾,奖品发完了" << std::endl;
		//奖品已经发完,后面的人就不能抽奖了
		m_activity->setState(m_activity->getDispenseOutState());
	}
}

//dispenseoutstate.h
#pragma once
#include <iostream>
#include "state.h"
class RaffleActivity;
//奖品发放完毕状态
class DispenseOutState :public State {
public:
	DispenseOutState(RaffleActivity*activity);
	void deductMeney() override;
	bool raffle() override;
	void dispensePrize() override;
private:
	RaffleActivity* m_activity;
};

//dispenseoutstate.cc
#include "dispenseoutstate.h"
#include "raffleactivity.h"
DispenseOutState::DispenseOutState(RaffleActivity*activity) {
	m_activity = activity;
}
void DispenseOutState::deductMeney(){
	std::cout << "奖品已经发完了,请下次参加" << std::endl;
}
bool DispenseOutState::raffle(){
	std::cout << "奖品已经发完了,请下次参加" << std::endl;
	return false;
}
void DispenseOutState::dispensePrize(){
	std::cout << "奖品已经发完了,请下次参加" << std::endl;
}

//canrafflestate.h
#pragma once
#include <iostream>
#include <time.h>
#include "state.h"
class RaffleActivity;
//能抽奖状态
class CanRaffleState :public State {
public:
	CanRaffleState(RaffleActivity*activity);
	//已经扣除积分了,不能再扣了
	void deductMeney();
	//可以抽奖,根据抽奖情况改成新的状态
	bool raffle() override;
	void dispensePrize() override;
private:
	RaffleActivity* m_activity;
};
//canrafflestate.cc
#include "canrafflestate.h"
#include "raffleactivity.h"
CanRaffleState::CanRaffleState(RaffleActivity*activity) {
	srand(time(NULL));
	m_activity = activity;
}
//已经扣除积分了,不能再扣了
void CanRaffleState::deductMeney(){
	std::cout << "已经扣过积分了" << std::endl;
}
//可以抽奖,根据抽奖情况改成新的状态
bool CanRaffleState::raffle(){
	std::cout << "正在抽奖..." << std::endl;
	int result = rand() % 10;
	if (!result) {
		//将activity的状态设置为发放奖品的状态
		m_activity->setState(m_activity->getDispenseState());
		return true;
	}
	else {
		std::cout << "很遗憾没有抽中奖品" << std::endl;
		//将activity的状态设置为不能抽奖的状态
		m_activity->setState(m_activity->getNoRaffleState());
		return false;
	}
}
void CanRaffleState::dispensePrize(){
	std::cout << "没中奖,不能发放奖品" << std::endl;
}
//raffleactivity.h
#pragma once
#include <iostream>
#include "state.h"
#include "canrafflestate.h"
#include "dispenseoutstate.h"
#include "dispensestate.h"
#include "norafflestate.h"
class RaffleActivity {
public:
	RaffleActivity(int count) {
	 //初始化当前状态为 不能抽奖状态
	 this->state = getNoRaffleState();
	 //初始化奖品数量
	 this->count = count;
	}
	//扣分,调用当前状态的deductMoney
	void deductMoney()
	{
	  state->deductMeney();
	}
	//抽奖
	void raffle()
	{
		//如果抽中奖了,则领奖品
		if (state->raffle())
		{
			state->dispensePrize();
		}
	}
	State* getState()const {
		return state;
	}
	void setState(State*const state) {
		this->state = state;
	}
	int getCount() {
		return count--;
	}
	void setCount(const int count) {
		this->count = count;
	}
	State* getNoRaffleState()const {
		return noRaffleState;
	}
	void setNoRaffleState(State* const noRaffleState)
	{
		this->noRaffleState = noRaffleState;
	}
	State* getCanRaffleState() const
	{
		return canRaffleState;
	}
	void setCanRaffleState(State* const canRaffleState)
	{
		this->canRaffleState = canRaffleState;
	}
	State* getDispenseState() const
	{
		return dispenseState;
	}
	void setDispenseState(State* const dispenseState)
	{
		this->dispenseState = dispenseState;
	}
	State* getDispenseOutState() const
	{
		return dispenseOutState;
	}
	void setDispenseOutState(State* const dispenseOutState)
	{
		this->dispenseOutState = dispenseOutState;
	}
private:
	//state表示活动当前的状态
	State* state = nullptr;
	//奖品数量
	int count = 0;
	//四个属性 表示四种状态
	State* noRaffleState = new NoRaffleState(this);
	State* canRaffleState = new CanRaffleState(this);
	State* dispenseState = new DispenseState(this);
	State* dispenseOutState = new DispenseOutState(this);
};

四、状态模式优缺点

优点:

  • 遵循单一职责原则
  • 开闭原则的良好实践
  • 消除庞大的条件分支语句
  • 提高代码可维护性
  • 状态转换更加安全可控
  • 便于单元测试

缺点:

  • 类数量爆炸
  • 状态转移逻辑可能分散
  • 上下文与状态间的循环依赖
  • 内存和性能开销
  • 状态共享困难
  • 过度设计风险
相关推荐
zmzb01037 小时前
C++课后习题训练记录Day120
开发语言·c++
ximu_polaris7 小时前
设计模式(C++)-行为型模式-迭代器模式
c++·设计模式·迭代器模式
tjl521314_217 小时前
01C++ 类定义与访问控制(封装)
java·开发语言·c++
c++之路18 小时前
C++信号处理
开发语言·c++·信号处理
故事还在继续吗20 小时前
C++20关键特性
开发语言·c++·c++20
青少儿编程课堂20 小时前
2026青少儿信息素养大赛备赛指南!Python/Scratch/C++备考要点
开发语言·c++·python
旖-旎21 小时前
深搜练习(电话号码字母组合)(3)
c++·算法·力扣·深度优先遍历
AIFarmer21 小时前
【无标题】
开发语言·c++·算法
huzhongqiang21 小时前
Python 单例模式的几种实现方式:朴素才是王道
设计模式