状态模式的原理其实很简单:核心一个对象的行为取决于它的状态。也就是说如果一个对象的状态发生了变化,那么该对象的行为也要发生相应的改变。
虽然上面一句话说出了状态模式的核心所在,在这里还是要简单的分析下,算是加深理解!
按照上图以及面向对象的思维,状态模式设计到两种对象: 1、状态持有者对象(StateHolder)或者其他资料上所说的Context,本文为了方便说明也就沿袭Context这个惯例。 2、状态对象(States),一个状态持有者若干个状态。
然后就是定制状态切换的规则了,当然这个因需求而异,比如有的状态是在状态持有者内部自己切换的,是状态持有者主动进行状态切换以便进行下一个状态的操作。有的状态是由外部改变的,Context被动的接受状态的改变而进行相应的处理。网上各种介绍该模式的博文都是举一个简单的例子,本文也不免俗,就举个例子吧。
比如QQ,具有在线、离线、离开等状态,QQ在不同的状态会处理不同逻辑,比如在线状态下可以qq.sendMessage(),离线状态下提示登陆qq.goLogin(),离开状态下会给对方一个提醒qq.sendAlert()等。在这里QQ就是状态持有者,也就是状态模式中的Context对象。
非状态模式下的实现:如果用非状态模式来处理的话,可能会有如下两种的代码的实现:
private int state = 0;
public void execute() {
if (state == 0) {//离线状态
goLogin();
} else if (state == 1) {//在线状态
sendMsg();
} else if (state == 2) {//离开状态
sendAlert();
}
}
public void switchState(int newState) {
state = newState;
}
上面这种代码可扩展性不强,如果在增加许多状态的话,势必充斥着大量的if else 逻辑,随着状态的增多execute方法的代码量积聚增加。
状态模式实现的例子设计一个QQState接口:
public interface QQState {
void doAction(QQ qq);
}
实现离线、在线、离开状态的类:
//离线状态
public class OfflineState implements QQState {
@Override
public void doAction(QQ qq) {
qq.goLogin();
}
}
//在线状态
public class OnLineState implements QQState {
@Override
public void doAction(QQ qq) {
qq.sendMsg();
}
}
//离开状态
public class LeaveState implements QQState {
@Override
public void doAction(QQ qq) {
qq.sendAlert();
}
}
实现原理很简单,比如如果是离线状态,则qq这个状态持有者调用qq.goLoin()进行登陆操作。现在是时候看看状态持有者对象QQ的具体实现了:
public class QQ {
//持有一个状态
private QQState qqState;
public QQ() {
//初始化为离线状态
qqState = new OfflineState();
}
public void switchState(QQState newState) {
this.qqState = newState;
}
public void execeute() {
qqState.doAction(this);
}
//在线状态下发送消息
protected void sendMsg() {
System.out.println("美女你好?");
}
//向对方发出消息
protected void sendAlert() {
System.out.println("我现在不在电脑旁");
}
//去登陆
protected void goLogin() {
System.out.println("已离线,请重新登陆");
}
}
QQ 对象持有一个状态类的引用,且提供了switchState来切换状态信息。客户端代码如下:
public static void main(String args[]) {
QQ qq = new QQ();
qq.execeute();
System.out.println("--------------");
//切换成线上状态
qq.switchState(new OnLineState());
qq.execeute();
System.out.println("-------------");
//切换成离开状态
qq.switchState(new LeaveState());
qq.execeute();
}
运行效果如下:
已离线,请重新登陆
-----------------------------
美女你好?
-----------------------------
我现在不在电脑旁
此时execute方法仅一行qqState.doAction(this)就可以搞定。当然了,如果状态多的话,也会创建大量的状态类,是的对象激增,这也是状态模式的缺点之一。
与观察者模式的不同: 状态模式当状态发生改变时,响应变化的是状态持有者本身,而观察者模式则是被观察者自身发生改变时,通知不同的观察者对执行相应的改变。也就是说状态模式是外部或者内部的状态影响自身,而观察者模式则是影响别人(Observer)
至于与策略模式的区别,请参考博主的《设计模式之策略模式》 到此为止,状态模式讲解完毕,如果不当之处欢迎批评指正。