Java设计模式系列之状态模式
状态模式(State)的定义
定义对象间的一种一对多的依赖关系,当一个对象的状态(对象内部的属性,可以理解成是对象的某个字段或者方法)发生改变时,所有依赖于它的对象都得到通知并被自动更新。允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类
状态模式(State)适用性
1.一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为。
2.一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。
这个状态通常用一个或多个枚举常量表示。
通常,有多个操作包含这一相同的条件结构。
State模式将每一个条件分支放入一个独立的类中。
这使得你可以根据对象自身的情况将对象的状态作为一个对象,这一对象可以不依赖于其他对象而独立变化。
状态模式(State)的参与者
1.Context
定义客户感兴趣的接口。
维护一个ConcreteState子类的实例,这个实例定义当前状态。
2.State
定义一个接口以封装与Context的一个特定状态相关的行为。
3.ConcreteStatesubclasses
每一子类实现一个与Context的一个状态相关的行为。
状态模式(State)的UML类图
具体代码实现:
定义State
//定义和Context中的状态相对应的行为
public interface State {
//获取天气情况
String getState();
}
定义Context
//定义当前的状态
public class Context { private State state; public State getState() {
return state;
} public void setState(State state) {
this.state = state;
}
public String stateMessage(){
return state.getState();
}
}
定义ConcreteStatesubclasses
class Sunshine implements State{ @Override
public String getState() { return "晴天";
} }
class Rain implements State{ @Override
public String getState() { return "下雨";
} }
测试一下
public class StateTest { public static void main(String args[]){ Context context=new Context();
context.setState(new Rain()); System.out.println(context.stateMessage()); context.setState(new Sunshine());
System.out.println(context.stateMessage());
}
}
运行结果:
下雨
晴天
接下来我们用Java编程思想中的一个例子来讲解一下状态模式
我们学习了多态,看起来似乎所有的东西都可以去继承,因为多态是一个如此巧妙的工具。事实上,当我们使用现成的类建立新类时,如果首先考虑使用继承技术,反倒会加重我们的设计负担,使得事情变得复杂起来。
更好的设计思想是首先选择"组合",尤其是不能十分确定应该使用哪一种方式的时候。组合不会强制我们的程序设计进入继承的层次结构中。而且,组合更加灵活,因为它可以动态选择类型(因此也就选择了行为),想法,继承在编译时就需要知道确定的类型,下面是具体代码体现:
//相当于状态模式中的state
class Actor { public void act(){
}
}
//相当于状态模式中的ConcreteStateSubclassess
class HappyActor extends Actor{
public void act(){
System.out.println("HappyActor");
}
}
class SadActor extends Actor{
public void act(){
System.out.println("SadActor");
}
}
//相当于状态模式中的Context
class Stage{
private Actor actor=new HappyActor();
//改变引用actor的指向的具体类型
public void change(){
actor=new SadActor();
}
//根据状态的不同执行不同的行为
public void performPlay(){
actor.act();
}
}
测试一下:
public class Transmogrify { /**
* @param args
*/
public static void main(String[] args) { Stage stage=new Stage();
stage.performPlay();
stage.change();
stage.performPlay();
} }
运行结果:
HappyActor
SadActor
程序分析:在这里,Stage对象包含一个对Actor的引用,而Actor被初始化为HappyActor对象,这意味着performPlay()会产生某种特殊行为。既然引用在运行时可以和另一个不同的对象重新绑定起来,SadActor对象的引用可以在actor中被替换,然后由performPlay()产生的行为也随之改变,这样一来,我们在运行期间获得了动态灵活性。与此相反的是,我们不能在运行期间决定继承不同的对象,因为它要求在编译期间完全确定下来。
大家是不是觉得状态模式和策略模式不是一样的吗?我们讲一下他们之间的区别和联系:
状态模式和策略模式的区别和联系(取自知乎网友的回答,很精辟):
状态模式将各个状态所对应的操作分离开来,即对于不同的状态,由不同的子类实现具体操作,不同状态的切换由子类实现,当发现传入参数不是自己这个状态所对应的参数,则自己给Context类切换状态;而策略模式是直接依赖注入到Context类的参数进行选择策略,不存在切换状态的操作联系。
最新文章
- thunkify 模块
- 0929mysql前缀索引如何找到合适的位数
- JavaScript写一个拼图游戏
- php 生成 Json
- c++之路进阶——bzoj3343(教主的魔法)
- Jquery 计算表格某一列的合计
- oracle 日期字段的处理
- 解决wordpress上传的文件尺寸超过 php.ini 中定义的 upload_max_filesize 值。
- 五分钟学习React(三):纯HTML代码搭建React应用
- CCA更新流程分析
- js中将字符串作为函数名来调用的方法
- Java问题解决:使用maven install 和 package时出错
- python第十九天 关于方法,函数
- Linux运行Java出现“Exception in thread ";main"; java.lang.OutOfMemoryError: Java heap space”报错
- 工控安全入门之Ethernet/IP
- python 线程 进程
- JavaScript--事件对象(25)
- [APP] Android 开发笔记 001-环境搭建与命令行创建项目
- 01: JavaScript实例
- phpStudy6——php导出可以设置样式的excel表格
热门文章
- Linux下拆分大文件
- When you’re nearly 40 and unmarried, and you realize you’re going to be okay
- Failed to initialize monitor Thread: Unable to establish loopback connection解决方法
- [NYIST16]矩形嵌套(DP,最长上升子序列)
- UVa 1328 (KMP求字符串周期) Period
- [转]ASP.NET数据库连接字符串总结
- 【转】iOS学习之Autolayout(代码添加约束) -- 不错不错
- 【转】Linux 之 /etc/profile、~/.bash_profile 等几个文件的执行过程
- Entity Framework中编辑时错误ObjectStateManager 中已存在具有同一键的对象
- C# 中LinkLabel的简单使用