状态模式(State Pattern)
状态模式,当一个对象的内在状态改变时允许改变其行为,这个对象看起来就像是改变了其类。状态模式主要解决的是当控制一个对象的状态条件表达式过于复杂时的情况。如果一个对象状态的判断逻辑过于复杂,会不便于后期系统的维护以及不利于系统扩展。在状态模式中,将状态的判断逻辑转移到了表示不同状态的一系列类中,这样每一个类代表着一种状态,每种状态的处理功能逻辑单一化、专业化,这样就大大简化了判断的处理逻辑,同时也增强了系统的可读性,更利于系统维护和扩展。
介绍
意图:允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类。
使用场景:
1. 一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变其行为。
2. 一个操作中含有庞大的分支结构,并且这些分支决定于对象的状态。
优点:
1. 封装了转换规则。
2. 枚举可能的状态,在枚举状态之前需要确定状态种类。
3. 将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象行为。
4. 允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块。
5. 可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。
缺点:
1. 状态模式的使用必然会增加系统类和对象的个数。
2. 状态模式的结构和实现都较为复杂,如果使用不当讲导致程序结构和代码的混乱。
3. 状态模式对开闭原则的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态切换的源代码,否则无法切换到新增状态,而且修改某个状态类的行为也需修改对应类的源代码。
注意事项:在行为受状态约束的时候使用状态模式,而且状态一般不超过5个。
实现
在状态模式的实例中,我们模拟一个文本文件编辑和预览的功能。编辑和预览两种状态,分别对应不同的操作。
步骤 1
创建一个状态接口。
IState.java
package com.mrcsj.test.study.state;
/**
* 状态接口
* @author admin
* @version 1.0
* @created 19-十二月-2016 17:07:07
*/
public interface IState {
/**
* 添加
*
* @param context
*/
public void add(Context context);
/**
* 状态转换
*
* @param context
* @param mode
*/
public void convertState(Context context, int mode);
/**
* 修改
*
* @param context
*/
public void modify(Context context);
/**
* 保存
*
* @param context
*/
public void save(Context context);
/**
* 查看
*
* @param context
*/
public void view(Context context);
}
步骤 2
创建一下上下文,用来切换当前编辑和预览状态。
Context.java
package com.mrcsj.test.study.state;
/**
* 上下文环境,用来决定使用哪一种状态
* @author admin
* @version 1.0
* @created 19-十二月-2016 17:07:07
*/
public class Context {
public static final int EDIT_MODE = 0;
public static final int PREVIEW_MODE = 1;
private IState state;
public Context(){
}
public void finalize() throws Throwable {
}
/**
*
* @param state
*/
public void changeState(IState state){
this.state = state;
}
/**
* 改变状态
*
* @param mode
*/
public void doWork(int mode){
this.state.convertState(this, mode);
this.state.add(this);
this.state.save(this);
this.state.modify(this);
this.state.view(this);
}
}//end Context
步骤 3
创建编辑和预览两种状态实现类。
编辑
EditState.java
package com.mrcsj.test.study.state;
/**
* @author admin
* @version 1.0
* @created 19-十二月-2016 17:07:07
*/
public class EditState implements IState {
public EditState(){
}
public void finalize() throws Throwable {
}
/**
* 添加
*
* @param context
*/
public void add(Context context){
System.out.println("【编辑模式】。。。新增");
}
/**
* 状态转换
*
* @param context
* @param mode
*/
public void convertState(Context context, int mode){
if(mode == Context.PREVIEW_MODE) {
context.changeState(new PreviewState());
}
}
/**
* 修改
*
* @param context
*/
public void modify(Context context){
System.out.println("【编辑模式】。。。修改");
}
/**
* 保存
*
* @param context
*/
public void save(Context context){
System.out.println("【编辑模式】。。。保存");
}
/**
* 查看
*
* @param context
*/
public void view(Context context){
System.out.println("【编辑模式】。。。查看");
}
}//end EditState
预览
PreviewState.java
package com.mrcsj.test.study.state;
/**
* @author admin
* @version 1.0
* @created 19-十二月-2016 17:07:07
*/
public class PreviewState implements IState {
public PreviewState(){
}
public void finalize() throws Throwable {
}
/**
* 添加
*
* @param context
*/
public void add(Context context){
System.out.println("【预览模式】。。。无新增功能");
}
/**
* 状态转换
*
* @param context
* @param mode
*/
public void convertState(Context context, int mode){
if(mode == Context.EDIT_MODE) {
context.changeState(new EditState());
}
}
/**
* 修改
*
* @param context
*/
public void modify(Context context){
System.out.println("【预览模式】。。。无修改功能");
}
/**
* 保存
*
* @param context
*/
public void save(Context context){
System.out.println("【预览模式】。。。无保存功能");
}
/**
* 查看
*
* @param context
*/
public void view(Context context){
System.out.println("【预览模式】。。。查看");
}
}//end PreviewState
步骤 4
创建客户端,进行测试。
Client.java
package com.mrcsj.test.study.state;
import java.util.Random;
/**
* 客户端
* @author admin
* @version 1.0
* @created 19-十二月-2016 17:07:06
*/
public class Client {
public Client(){
}
public void finalize() throws Throwable {
}
public static void main(String[] args) {
Context context = new Context();
context.changeState(new EditState());
Random r = new Random();
for(int i = 0; i < 5; i ++) {
int x = r.nextInt(2);
System.out.println("当前模式:" + (x == 0 ? "编辑模式" : x == 1 ? "预览模式" : ""));
context.doWork(x);
}
}
}//end Client
步骤 5
验证输出。
当前模式:预览模式
【预览模式】。。。无新增功能
【预览模式】。。。无保存功能
【预览模式】。。。无修改功能
【预览模式】。。。查看
当前模式:预览模式
【预览模式】。。。无新增功能
【预览模式】。。。无保存功能
【预览模式】。。。无修改功能
【预览模式】。。。查看
当前模式:预览模式
【预览模式】。。。无新增功能
【预览模式】。。。无保存功能
【预览模式】。。。无修改功能
【预览模式】。。。查看
当前模式:预览模式
【预览模式】。。。无新增功能
【预览模式】。。。无保存功能
【预览模式】。。。无修改功能
【预览模式】。。。查看
当前模式:编辑模式
【编辑模式】。。。新增
【编辑模式】。。。保存
【编辑模式】。。。修改
【编辑模式】。。。查看