【设计模式二十三之状态StatePattern模式】状态模式StatePattern

细说状态模式

提示:
博主:章飞 _906285288的博客
博客地址:http://blog.csdn.net/qq_29924041


细说状态模式

状态模式顾明思议,此设计模式肯定是为了整合状态来实现的,在实际开发过程中是不是经常会遇到,使用if-else或者switch去进行差分行为的,举个栗子,比如说一个媒体播放器,它就有播放(Started)状态,有暂停(Paused)状态,有停止(Stoped)状态,也有销毁(Destoryed)状态,这些状态规定了起当前是由哪一种行为触发导致的。汽车有自己的状态,有(ACC)状态,有行驶状态,有停止状态,电梯有电梯的开门,关门,上,下,等状态。这些其实都是用于区分事物的某一种行为。同时也规定了在该状态下,其可以演变成下一种的哪一种行为
比如说电梯,在开门的时候不可能直接转成上,或者下状态。上状态中也不可能开门,或者关门吧

定义

状态模式: 当一个对象内在状态发生改变的时候,允许其改变行为,这个对象看起来像是改变了其类。
通俗点来说,就是梳理出事物的状态模型,然后当某种状态发生改变的时候,会改变其下一个状态演变的类型。

状态模式的核心是封装,状态的变更会引起行为的变更,从外部看起来就好像是这个对象对应的类发生了改变一样

UML模型

状态模式UML设计图
从UML设计图中可以看出来,当前状态模式下的几个元素:
1:State 抽象的状态角色,是接口或者抽象类,主要负责对象的状态的定义,并且封装环境角色以实现状态角色

2:ConcreteState 具体的状态角色,每一个具体状态角色必须完成两个职责,一个是本状态的行为管理以及趋向状态处理,通俗的说就是本状态下要做的事情,以及本状态下如何过度到其它的状态

3:Context 定义的是客户端需要的接口,主要负责具体状态的切换

基于UML的代码
package src.com.zzf.designpattern.statepattern.uml;

public abstract class State {
	//定义一个环境角色,提供子类访问
	protected Context context;
	
	public void setContext(Context _context) {
		this.context = _context;
	}
	
	//行为1
	public abstract void handle1();
	
	//行为2
	public abstract void handle2();
	
}

package src.com.zzf.designpattern.statepattern.uml;

public class ConcreteState1 extends State {

	@Override
	public void handle1() {
		// TODO Auto-generated method stub
		//本状态下需要处理的逻辑
		System.out.println("ConcreteState1 handle1");
	}

	@Override
	public void handle2() {
		// TODO Auto-generated method stub
		super.context.setCurrentState(Context.STATE2);
		super.context.handle2();
	}

}

package src.com.zzf.designpattern.statepattern.uml;

public class ConcreteState2 extends State {

	@Override
	public void handle1() {
		// TODO Auto-generated method stub
		super.context.setCurrentState(Context.STATE1);
		super.context.handle1();
	}

	@Override
	public void handle2() {
		// TODO Auto-generated method stub
		// TODO Auto-generated method stub
				//本状态下需要处理的逻辑
				System.out.println("ConcreteState2 handle2");
	}

}

package src.com.zzf.designpattern.statepattern.uml;

public class Context {
	//定义状态
	public final static State STATE1 = new ConcreteState1();
	public final static State STATE2 = new ConcreteState2();
	//当前状态
	private State CurrentState;
	//获得当前状态
	public State getCurrentState() {
		return CurrentState;
	}
	//设置当前状态
	public void setCurrentState(State currentState) {
		this.CurrentState = currentState;
		this.CurrentState.setContext(this);
	}
	//行为委托
	public void handle1(){
		this.CurrentState.handle1();
	}
	
	public void handle2(){
		this.CurrentState.handle2();
	}
}

package src.com.zzf.designpattern.statepattern.uml;

public class Client {
	public static void main(String[] args) {
		//初始化环境角色
		Context context = new Context();
		//初始化状态
		context.setCurrentState(new ConcreteState1());
		//执行行为
		context.handle1();
		context.handle2();
	}
}

从上面的案例中看到有以下几个角色:
1:State:主要是抽象的状态行为
2:ConcreteState1和ConcreteState2主要是具体的状态
3:Context是上下文,其主要作用是为了连接所有的状态。

场景一

场景

此场景主要来源于设计模式之禅中的状态模式,根据电梯的状态来进行解析的,电梯有四种状态,打开,关闭,运行,以及停止状态,从这4中状态中来解析出其状态行为和状态变迁。

代码
package src.com.zzf.designpattern.statepattern.demo2;

/**
 * 抽象的电梯状态类,主要是定义了其所有状态下的行为模式
 * @author zhangfei.zhou
 *
 */
public abstract class LiftState {
	protected Context mContext;
	
	public void setContext(Context _mContext){
		this.mContext = _mContext;
	}
	
	/**
	 * 打开状态
	 */
	public abstract void open();
	
	/**
	 * 关闭状态
	 */
	public abstract void close();
	
	/**
	 * 运行状态
	 */
	public abstract void run();
	
	/**
	 * 停止状态
	 */
	public abstract void stop();
}

package src.com.zzf.designpattern.statepattern.demo2;


public class OpenningState extends LiftState{

	@Override
	public void open() {
		// TODO Auto-generated method stub
		System.out.println("电梯门开启");
	}

	@Override
	public void close() {
		// TODO Auto-generated method stub
		super.mContext.setLiftState(Context.closeingState);
		super.mContext.getLiftState().close();
	}

	@Override
	public void run() {
			//电梯门开着状态下,是无法运行的
		System.out.println("电梯门开着状态下,是无法运行的");
	}

	@Override
	public void stop() {
			//电梯门开着的情况下,是无法进行停止的
		System.out.println("电梯门开着的情况下,是无法进行停止的");
	}

}

package src.com.zzf.designpattern.statepattern.demo2;

public class ClosingState extends LiftState{

	@Override
	public void open() {
		// TODO Auto-generated method stub
		super.mContext.setLiftState(Context.closeingState);
		super.mContext.getLiftState().open();
	}

	@Override
	public void close() {
		// TODO Auto-generated method stub
		System.out.println("电梯门关闭。。。");
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		super.mContext.setLiftState(Context.runningState);
		super.mContext.getLiftState().run();
	}

	@Override
	public void stop() {
		// TODO Auto-generated method stub
		super.mContext.setLiftState(Context.stoppingState);
		super.mContext.getLiftState().stop();
	}

}

package src.com.zzf.designpattern.statepattern.demo2;


public class RunningState extends LiftState {

	@Override
	public void open() {
		// TODO Auto-generated method stub
		System.out.println("运行状态下,无法进行打开电梯门");
	}

	@Override
	public void close() {
		// TODO Auto-generated method stub
		System.out.println("运行状态下 不可能进行关门");
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		System.out.println("电梯上下跑");
	}

	@Override
	public void stop() {
		// TODO Auto-generated method stub
		super.mContext.setLiftState(Context.stoppingState);
		super.mContext.getLiftState().stop();
	}

}

package src.com.zzf.designpattern.statepattern.demo2;


public class StoppingState extends LiftState {

	@Override
	public void open() {
		// TODO Auto-generated method stub
		super.mContext.setLiftState(Context.openningState);
		super.mContext.getLiftState().open();
	}

	@Override
	public void close() {
		// TODO Auto-generated method stub
		System.out.println("停止状态下,门本来就是关闭的 不可能再关闭");
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		super.mContext.setLiftState(Context.runningState);
		super.mContext.getLiftState().run();
	}

	@Override
	public void stop() {
		// TODO Auto-generated method stub
		System.out.println("电梯stop状态");
	}

}

package src.com.zzf.designpattern.statepattern.demo2;


public class Context {
	// 定义出所有的电梯状态
	public final static OpenningState openningState = new OpenningState();
	public final static ClosingState closeingState = new ClosingState();
	public final static RunningState runningState = new RunningState();
	public final static StoppingState stoppingState = new StoppingState();

	LiftState mLiftState;

	public void setLiftState(LiftState liftState) {
		this.mLiftState = liftState;
		this.mLiftState.setContext(this);
	}

	public LiftState getLiftState() {
		return mLiftState;
	}

	public void open() {
		this.mLiftState.open();
	}

	public void close() {
		this.mLiftState.close();
	}

	public void run() {
		this.mLiftState.run();
	}

	public void stop() {
		this.mLiftState.stop();
	}
}

package src.com.zzf.designpattern.statepattern.demo2;


/**
 * 注意:::::而且状态模式使用时对象的状态最好不要超过五个,防止你写子类写疯掉。
 * 
 * 当一个对象内在状态
	改变时允许其改变行为,这个对象看起来像是改变了其类
 * @author Administrator
 *	
 * 也就是说状态模式封装的非常好,状态的变更,引起了行为的变更,从外部看起来就好像这个对象对应的类发生了改变一样
 * 
 * 
 * 首先是避免了过多的swith…case 或者if..else 语句的使用,避免了程序
的复杂性;其次是很好的使用体现了开闭原则和单一职责原则,每个状态都是一个子类,你要增加状态就
增加子类,你要修改状态,你只修改一个子类就可以了;最后一个好处就是封装性非常好,这也是状态模
式的基本要求,状态变换放置到了类的内部来实现,外部的调用不用知道类内部如何实现状态和行为的变
换。
 */
public class Client {
	public static void main(String[] args) {
		Context mContext = new Context();
		mContext.setLiftState(new OpenningState());
		mContext.close();
		mContext.run();
		mContext.stop();
	}
}

以上则是从电梯状态角度来解析出状态类型

场景二

场景

有过媒体播放器相关的经验的话,都知道媒体音乐播放器的各种状态吧,IDLE空闲状态,PREPARED准备状态,STARTED播放状态,PAUSED暂停状态,STOPED状态,REALEASED 释放状态等等,这一系列状态组成了播放器在播放状态是的各种切换,比如空闲状态下,只能往准备状态迁移,即在空闲状态中,下一步只能做转成准备,
开始播放状态时,此时只能往暂停和停止状态迁移

代码
package src.com.zzf.designpattern.statepattern.player;

/**
 * 播放器类
 * @author zhangfei.zhou
 *
 */
public class MediaPlayer {
	public  void prepare(){
		System.out.println("MediaPlayer prepare");
	}
	
	public  void start(){
		System.out.println("MediaPlayer start");
	}
	
	public  void pause(){
		System.out.println("MediaPlayer pause");
	}
	
	public  void stop(){
		System.out.println("MediaPlayer stop");
	}
	
	public  void release(){
		System.out.println("MediaPlayer release");
	}
	
	public  void reset(){
		System.out.println("MediaPlayer reset");	
	}
}

package src.com.zzf.designpattern.statepattern.player;

public abstract class PlayerState {
	
	Context context;
	MediaPlayer mediaPlayer = null;
	public void setMediaPlayer(MediaPlayer _mediaPlayer) {
		this.mediaPlayer =_mediaPlayer;
	}
	public void setContext(Context _context) {
		this.context = _context;
	}
	
	public abstract void prepare();
	
	public abstract void start();
	
	public abstract void pause();
	
	public abstract void stop();
	
	public abstract void release();
	
	public abstract void reset();
	
	
}

package src.com.zzf.designpattern.statepattern.player;

/**
 * 此状态是播放器的空闲状态
 * @author zhangfei.zhou
 * 如果当前是空闲状态的话,播放器的下一个状态只能是准备状态
 */
public class PlayerIdleState extends PlayerState{

	@Override
	public void prepare() {
		// TODO Auto-generated method stub
		if(super.context != null){
			super.context.setCurrentPlayerState(Context.PREPARE_STATE);
			super.context.prepare();
		}
	}

	@Override
	public void start() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void pause() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void stop() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void release() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void reset() {
		// TODO Auto-generated method stub
		if(super.mediaPlayer != null){
			super.mediaPlayer.reset();
		}
	}

}

package src.com.zzf.designpattern.statepattern.player;

/**
 * 准备状态,准备状态是可以
 * start
 * release
 * reset的
 * @author zhangfei.zhou
 *
 */
public class PlayerPrepareState extends PlayerState{

	@Override
	public void prepare() {
		// TODO Auto-generated method stub
		//执行当前需要准备状态下需要处理的相关事件资源
		if(mediaPlayer != null){
			mediaPlayer.prepare();
		}
	}

	@Override
	public void start() {
		// TODO Auto-generated method stub
		if(super.context != null){
			super.context.setCurrentPlayerState(Context.START_STATE);
			super.context.start();
		}
	}

	@Override
	public void pause() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void stop() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void release() {
		// TODO Auto-generated method stub
		if(super.context != null){
			super.context.setCurrentPlayerState(Context.RELEASED_STATE);
			super.context.release();
		}
	}

	@Override
	public void reset() {
		// TODO Auto-generated method stub
		if(super.context != null){
			super.context.setCurrentPlayerState(Context.IDEL_STATE);
			super.context.reset();
		}
	}

}

package src.com.zzf.designpattern.statepattern.player;

/**
 * 播放状态
 * @author zhangfei.zhou
 *播放状态下,播放器开始播放
 */
public class PlayerStartedState extends PlayerState{

	@Override
	public void prepare() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void start() {
		// TODO Auto-generated method stub
		if(super.mediaPlayer != null){
			super.mediaPlayer.start();
		}
	}

	@Override
	public void pause() {
		// TODO Auto-generated method stub
		if(super.context != null){
			super.context.setCurrentPlayerState(Context.PAUSED_STATE);
			super.context.pause();
		}
	}

	@Override
	public void stop() {
		// TODO Auto-generated method stub
		if(super.context != null){
			super.context.setCurrentPlayerState(Context.STOPED_STATE);
			super.context.stop();
		}
	}

	@Override
	public void release() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void reset() {
		// TODO Auto-generated method stub
		
	}

}

package src.com.zzf.designpattern.statepattern.player;

/**
 * 此状态是暂停状态
 * 暂停状态时,主要播放器暂停
 * 然后暂停状态可以迁移成
 * 停止状态
 * 播放状态
 * 
 * @author zhangfei.zhou
 *
 */
public class PlayerPausedState extends PlayerState{

	@Override
	public void prepare() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void start() {
		// TODO Auto-generated method stub
		if(super.context != null){
			super.context.setCurrentPlayerState(Context.START_STATE);
			super.context.start();
		}
	}

	@Override
	public void pause() {
		// TODO Auto-generated method stub
		if(super.mediaPlayer != null){
			super.mediaPlayer.pause();
		}
	}

	@Override
	public void stop() {
		// TODO Auto-generated method stub
		if(super.context != null){
			super.context.setCurrentPlayerState(Context.STOPED_STATE);
			super.context.stop();
		}
	}

	@Override
	public void release() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void reset() {
		// TODO Auto-generated method stub
		
	}

}

package src.com.zzf.designpattern.statepattern.player;

/**
 * 停止状态
 * 停止状态播放器停止
 * 停止后可以继续播放
 * 停止后可以realse
 * 
 * @author zhangfei.zhou
 *
 */
public class PlayerStopedState extends PlayerState{

	@Override
	public void prepare() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void start() {
		// TODO Auto-generated method stub
		if(super.context != null){
			super.context.setCurrentPlayerState(Context.START_STATE);
			super.context.start();
		}
	}

	@Override
	public void pause() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void stop() {
		// TODO Auto-generated method stub
		if (super.mediaPlayer != null) {
			super.mediaPlayer.stop();
		}
	}

	@Override
	public void release() {
		// TODO Auto-generated method stub
		if(super.context != null){
			super.context.setCurrentPlayerState(Context.RELEASED_STATE);
			super.context.release();
		}
	}

	@Override
	public void reset() {
		// TODO Auto-generated method stub
		
	}

}

package src.com.zzf.designpattern.statepattern.player;

/**
 * 释放资源的状态 realsed状态
 * released状态时,此时播放器进行释放资源行为
 * 在realse状态下可以,重置播放器,将播放器变成idle状态
 * 
 * @author zhangfei.zhou
 *
 */
public class PlayerRealsedState extends PlayerState{

	@Override
	public void prepare() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void start() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void pause() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void stop() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void release() {
		// TODO Auto-generated method stub
		if (super.mediaPlayer != null) {
			super.mediaPlayer.release();
		}
	}

	@Override
	public void reset() {
		// TODO Auto-generated method stub
		if (super.context != null) {
			super.context.setCurrentPlayerState(Context.IDEL_STATE);
			super.context.reset();
		}
	}

}

package src.com.zzf.designpattern.statepattern.player;

public class Context {
	public final static PlayerPrepareState PREPARE_STATE =  new PlayerPrepareState();
	public final static PlayerStartedState START_STATE =  new PlayerStartedState();
	public final static PlayerPausedState PAUSED_STATE =  new PlayerPausedState();
	public final static PlayerStopedState STOPED_STATE =  new PlayerStopedState();
	public final static PlayerRealsedState RELEASED_STATE =  new PlayerRealsedState();
	public final static PlayerIdleState IDEL_STATE =  new PlayerIdleState();
	MediaPlayer mediaplayer = new MediaPlayer();
	PlayerState currentPlayerState;
	
	public PlayerState getCurrentPlayerState() {
		return currentPlayerState;
	}
	
	public void setCurrentPlayerState(PlayerState _currentPlayerState) {
		this.currentPlayerState = _currentPlayerState;
		currentPlayerState.setContext(this);
		currentPlayerState.setMediaPlayer(mediaplayer);
	}
	
	public  void prepare(){
		if(currentPlayerState != null){
			currentPlayerState.prepare();
		}
	}
	
	public  void start(){
		if(currentPlayerState != null){
			currentPlayerState.start();
		}
	}
	
	public  void pause(){
		if(currentPlayerState != null){
			currentPlayerState.pause();
		}
	}
	
	public  void stop(){
		if(currentPlayerState != null){
			currentPlayerState.stop();
		}
	}
	
	public  void release(){
		if(currentPlayerState != null){
			currentPlayerState.release();
		}
	}
	
	public  void reset(){
		if(currentPlayerState != null){
			currentPlayerState.reset();
		}
	}
}

package src.com.zzf.designpattern.statepattern.player;

public class Client {
	public static void main(String[] args) {
		Context context = new Context();
		context.setCurrentPlayerState(Context.IDEL_STATE);
		context.prepare();
		
		context.start();
		context.pause();
		
		context.start();
		context.stop();
		
		context.release();
		context.reset();
	}
}

以上代码是关于播放器状态的状态模式下的简易代码,其实可以看出来当状态很多的时候,这个时候状态与状态之间的切换相对来说是比较复杂的,所以状态模式的应用其实是看当前状态数量以及状态复杂度共同来确定的,不能一味的追求设计模式而使用设计模式,有时候也会是一些比较坑的设计

状态模式应用和注意事项

注意事项一

环境对象有两个不成文的约束:
1:把状态对象声明成静态常量,有几个状态对象就声明成几个静态常量
2:环境角色具有状态抽象角色定义的所有行为,具体执行使用委托的方式进行执行

注意事项二

首先是避免了过多的swith…case 或者if…else 语句的使用,避免了程序
的复杂性;其次是很好的使用体现了开闭原则和单一职责原则,每个状态都是一个子类,你要增加状态就增加子类,你要修改状态,你只修改一个子类就可以了;最后一个好处就是封装性非常好,这也是状态模式的基本要求,状态变换放置到了类的内部来实现,外部的调用不用知道类内部如何实现状态和行为的变化
但是如果状态过多的情况下,可能会导致子类的会扩展出很多,这个时候则会导致子类膨胀现象




欢迎继续访问,我的博客
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值