二十、状态模式

意图:允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类。

主要解决:对象的行为依赖于它的状态(属性),并且可以根据它的状态改变而改变它的相关行为。

何时使用:代码中包含大量与对象状态有关的条件语句。

如何解决:将各种具体的状态类抽象出来。

关键代码:通常命令模式的接口中只有一个方法。而状态模式的接口中有一个或者多个方法。而且,状态模式的实现类的方法,一般返回值,或者是改变实例变量的值。也就是说,状态模式一般和对象的状态有关。实现类的方法有不同的功能,覆盖接口中的方法。状态模式和命令模式一样,也可以用于消除 if...else 等条件选择语句。

应用实例: 1、打篮球的时候运动员可以有正常状态、不正常状态和超常状态。 2、曾侯乙编钟中,'钟是抽象接口','钟A'等是具体状态,'曾侯乙编钟'是具体环境(Context)。

优点: 1、封装了转换规则。 2、枚举可能的状态,在枚举状态之前需要确定状态种类。 3、将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。 4、允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块。 5、可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。

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

使用场景: 1、行为随状态改变而改变的场景。 2、条件、分支语句的代替者。

注意事项:在行为受状态约束的时候使用状态模式,而且状态不超过 5 个。

二十、状态模式

java版:

package com.shuang.state;

public class Context {
	private State state;

	public Context() {
	}
	
	public void setState(State state) {
		this.state = state;
	}
	public State getState() {
		return state;
	}
}

 

package com.shuang.state;


public class StartState implements State {

	public void doAction(Context context) {
		System.out.println("Player is in start state");
		context.setState(this);
	}

	public String toString() {
		return "Start State";
	}
}
package com.shuang.state;


public interface State {
	public void doAction(Context context);
}
package com.shuang.state;

public class StatePatternDemo {
	public static void main(String[] args) {
		Context context = new Context();
		
		StartState startState = new StartState();
		startState.doAction(context);
		
		System.out.println(context.getState().toString());
		
		StopState stopState = new StopState();
		stopState.doAction(context);
		
		System.out.println(context.getState().toString());
	}
}
package com.shuang.state;


public class StopState implements State {

	public void doAction(Context context) {
		System.out.println("Player is in stop state");
		context.setState(this);
	}

	public String toString() {
		return "Stop State";
	}
}

 

c++版:

#include<iostream>
using namespace std;
class Worker;
class State
{
public:
	virtual void doSomeThing(Worker *w) = 0;
};
class Worker
{
public:
	Worker();
	int getHour()
	{
		return m_hour;
	}
	void setHour(int hour)
	{
		m_hour = hour;
	}
	State *getCurrentState()
	{
		return m_currstate;
	}
	void setCurrentState(State * state)
	{
		m_currstate = state;
	}
	void doSomeThing()
	{
		m_currstate->doSomeThing(this);
	}
private:
	int m_hour;
	State *m_currstate;
};
class State1:public State
{
public:
	void doSomeThing(Worker *w);
};
class State2:public State
{
public:
	void doSomeThing(Worker *w);
};
void State1::doSomeThing(Worker *w)
{
	if (w->getHour() == 7 || w->getHour() == 8)
	{
		cout<<"吃早饭"<<endl;
	}
	else
	{
		delete w->getCurrentState();
		w->setCurrentState(new State2);
		w->getCurrentState()->doSomeThing(w);
	}
}
void State2::doSomeThing(Worker *w)
{
	if (w->getHour() == 9 || w->getHour() == 10)
	{
		cout << "工作" << endl;
	}
	else
	{
		delete w->getCurrentState();
		w->setCurrentState(new State1);
		cout << "当前时间点:" << w->getHour() << "未知状态" <<endl;
	}
}
Worker::Worker()
{
	m_currstate = new State1;
}
int main()
{
	Worker *w1 = new Worker;
	w1->setHour(7);
	w1->doSomeThing();

	w1->setHour(9);
	w1->doSomeThing();

	delete w1;
	system("pause");
	return 0;
}