设计模式---状态模式

95 阅读2分钟

定义

状态模式(State Pattern)是一种行为设计模式,它允许对象在内部状态改变时改变其行为,对象看起来似乎修改了其类。状态模式通过将每个状态封装到一个独立的对象中,并且将这些状态对象作为上下文对象的成员来实现状态的切换。

结构

  • Context(上下文) :持有一个 State 对象的实例,该实例定义了当前的状态。

  • State(抽象状态) :定义了一个接口,用于封装与 Context 的一个特定状态相关的行为。

  • ConcreteState(具体状态) :实现 State 接口,并根据 Context 的状态来实现具体行为。

优点

  • 简化状态转换逻辑:通过将每个状态的逻辑封装在独立的类中,使得状态转换的逻辑更加清晰和易于维护。

  • 开闭原则:可以轻松地添加新的状态而不需要修改现有的代码。

  • 提高灵活性:允许对象的行为在运行时发生变化,使得对象更具有灵活性。

代码示例

以下是一个关于文档发布流程的示例。文档有三种状态:草稿状态、审核中状态和发布状态。每个状态的行为不同,并且可以根据特定条件从一个状态切换到另一个状态,这里的条件为:周一至周三为草稿状态,周四至周五为审核状态,周六至周日为发布状态。

#include <iostream>
#include <string>

class Document;


// 抽象状态类
class State
{
public:
	virtual void handleRequest(Document& d) = 0;
	virtual ~State() = default;
};

// 上下文类
class Document
{
private:
	int weekday = 1;	// 周几
	State* state;		// 状态

public:
	Document(State* initialState) : state(initialState) {}


	void setState(State* val)
	{
		state = val;
	}

	void handleRequest()
	{
		state->handleRequest(*this);
	}

	int getDay()
	{
		return weekday;
	}

	void setDay(int val)
	{
		weekday = val;
	}
};


// 发布状态
class PublishedState : public State
{
public:
	void handleRequest(Document& d) override
	{
		std::cout << "Today is day" << d.getDay() << ", Document is in Published State." << std::endl;
	}
};



// 审核状态
class ModerationState : public State
{
public:
	void handleRequest(Document& d) override
	{
		if (d.getDay() < 6)		// 周四至周五为审核状态
		{
			std::cout << "Today is day" << d.getDay() << ", Document is in Moderation State." << std::endl;
		}
		else
		{
			d.setState(new PublishedState());
			d.handleRequest();
		}
	}
};


// 草稿状态
class DraftState : public State
{
public:
	void handleRequest(Document& d) override
	{
		if (d.getDay() < 4)		// 周一至周三为草稿状态
		{
			std::cout << "Today is day" << d.getDay() << ", Document is in Draft State." << std::endl;
		}
		else
		{
			d.setState(new ModerationState());
			d.handleRequest();
		}
	}
};




int main()
{
	Document* file = new Document(new DraftState());

	
	file->setDay(7);
	file->handleRequest();

	delete file;

	system("pause");
	return 0;
}