状态模式【行为模式C++】

1.概述

状态模式是一种行为设计模式, 让你能在一个对象的内部状态变化时改变其行为, 使其看上去就像改变了自身所属的类一样。

2.结构

  • **State(抽象状态类):**定义一个接口用来封装与上下文类的一个特定状态相关的行为,可以有一个或多个行为。
  • **ConcreteState(具体状态类):**作为抽象状态类的子类,每个子类实现一个与上下文类的一个状态相关的行为。每个具体状态类对应上下文类的一个具体状态,不同的具体状态类其行为有所不同。
  • Context(上下文类):上下文类中维护一个具体状态的实例,通常有多种状态,负责具体状态的切换。

3.实现

3.1 实例类比

在日常生活和工作开发中都有状态的问题。你如说马路上的红绿灯,这三个灯光就属于三种状态。再比如说我使用的文档系统,通常有草稿、审阅和批发部三种状态。

在以往的概念里,我们都会使用if...esle这类语句进行设计,但是这种设计一旦后期的需求发生了改变,那么维护起来相当的复杂!

一个 文档Document类。 文档可能会处于 草稿Draft 、 ​ 审阅中Moderation和 已发布Published三种状态中的一种。 文档的 publish发布方法在不同状态下的行为略有不同:

  • 处于**草稿**状态时, 它会将文档转移到审阅中状态。
  • 处于 审阅状态时, 如果当前用户是管理员, 它会公开发布文档。
  • 处于**已发布**状态时, 它不会进行任何操作。
3.2 具体实现
cpp 复制代码
#include <iostream>
#include <typeinfo>


class Context;

//抽象状态类
class State {
	
protected:
	Context *context_;

public:
	virtual ~State() {
	}

	void set_context(Context *context) {
		this->context_ = context;
	}

	virtual void Status() = 0;
	virtual void Handle() = 0;
};

//上下文类
class Context {
	
private:
	State *state_;

public:
	Context(State *state) : state_(nullptr) {
		this->TransitionTo(state);
	}
	~Context() {
		delete state_;
	}

	void TransitionTo(State *state) {
		std::cout << "Context: Transition to " << typeid(*state).name() << ".\n";
		if (this->state_ != nullptr)
			delete this->state_;
		this->state_ = state;
		this->state_->set_context(this);
	}
	
	void Request1() {
		this->state_->Status();
	}
	void Request2() {
		this->state_->Handle();
	}
};

//已发布状态
class PublishedState : public State {
public:
	void Status() override {
		std::cout << "处于已发布状态.\n";
	}
	void Handle() override {
		std::cout << "结束...\n";
	}
};

//审阅中状态
class ModerationState : public State {
public:
	void Status() override {
		std::cout << "处于审阅中状态.\n";
	};

	void Handle() override {
		this->context_->TransitionTo(new PublishedState);
	}
};


//草稿状态
class DraftState : public State {
public:
	void Status() override {
		std::cout << "处于草稿状态.\n";
	};

	void Handle() override {
		this->context_->TransitionTo(new ModerationState);
	}
};


/**
 * The client code.
 */
void ClientCode() {
	Context *context = new Context(new DraftState);
	context->Request1();
	context->Request2();
	//
	context->Request1();
	context->Request2();
	//
	context->Request1();
	context->Request2();
	delete context;
}

int main() {
	ClientCode();
	return 0;
}
3.3运行结果

4.状态设计模式优缺点

优点:

通常对有状态的对象进行编程,我们的解决方案是:思考可能存在的所有状态,然后使用 if-else 或 switch-case 语句来进行状态判断,然后再根据不同的状态进行不同的处理。

大量的if...else的缺点很明显

  1. **违背开闭原则:**当增加一种状态的时候, 需要修改原来的逻辑
  2. 当状态很多的时候, 代码段很长, 臃肿, 不容易维护, 可扩展性差.

状态模式可以很好地解决这个问题。封装了转换规则,消除了 if-else、switch-case 等条件判断语句,代码更有层次性,且具备良好的扩展力, 可维护性

缺点
  1. 状态模式的使用必然会增加系统类和对象的个数。
  2. 状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。
  3. 状态模式对"开闭原则"的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态,而且修改某个状态类的行为也需修改对应类的源代码。

5.应用场景

  1. 一个操作中含有庞大的多分支结构,并且这些分支取决于对象的状态。
  2. 对象的行为依赖于它的状态(例如某些属性值),状态的改变将导致行为的变化。
相关推荐
zzzhpzhpzzz13 天前
设计模式——备忘录模式
设计模式·备忘录模式
2401_8566545116 天前
这TOP3免费录屏软件,助你轻松跃升视频制作小能手
编辑器·音视频·视频编解码·视频·备忘录模式
tuodianke20 天前
Windows电脑桌面如何弄个好用的提醒备忘录?
笔记·科技·职场发展·软件需求·备忘录模式
麦克·唐21 天前
命令模式和备忘录模式实现undo、redo(C++)
c++·命令模式·备忘录模式
jzpfbpx24 天前
[go] 备忘录模式
开发语言·golang·备忘录模式
SunnyRivers24 天前
备忘录模式
备忘录模式
刷帅耍帅1 个月前
设计模式-备忘录模式
设计模式·备忘录模式
java_heartLake1 个月前
设计模式之备忘录模式
java·设计模式·备忘录模式
John_ToDebug1 个月前
设计模式之备忘录模式
c++·设计模式·备忘录模式
林小果11 个月前
备忘录模式
java·开发语言·设计模式·备忘录模式