设计模式是经验总结,是学习软件设计的有效方法,因此,了解和理解现有的设计模式,是提高软件设计的有效途径之一,这里将介绍相关的设计模式,并通过示例了理解其用法。
状态模式(State Pattern)
状态模式允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。
状态模式属于行为型模式。
意图: 允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类。
主要解决: 对象的行为依赖于它的状态(属性),并且可以根据它的状态改变而改变它的相关行为。
何时使用: 代码中包含大量与对象状态有关的条件语句。
如何解决: 将各种具体的状态类抽象出来。
关键代码: 通常命令模式的接口中只有一个方法。而状态模式的接口中有一个或者多个方法。而且,状态模式的实现类的方法,一般返回值,或者是改变实例变量的值。也就是说,状态模式一般和对象的状态有关。实现类的方法有不同的功能,覆盖接口中的方法。状态模式和命令模式一样,也可以用于消除 if…else 等条件选择语句。
应用实例: 1、打篮球的时候运动员可以有正常状态、不正常状态和超常状态。 2、曾侯乙编钟中,“钟是抽象接口”,“钟A”等是具体状态,“曾侯乙编钟”是具体环境(Context)。
优点: 1、封装了转换规则。 2、枚举可能的状态,在枚举状态之前需要确定状态种类。 3、将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。 4、允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块。 5、可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。
缺点: 1、状态模式的使用必然会增加系统类和对象的个数。 2、状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。 3、状态模式对"开闭原则"的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态,而且修改某个状态类的行为也需修改对应类的源代码。
使用场景: 1、行为随状态改变而改变的场景。 2、条件、分支语句的代替者。
注意事项: 在行为受状态约束的时候使用状态模式,而且状态不超过 5 个。
示例
这里以报警系统为例来说明状态模式。如果报警设备处于正常工作状态并发现有人,就会发出警报声;如果处于非工作状态(正常工作时间),就不应该发出警报声。状态图如下所示:
这里有两个状态,两个状态可以互相切换,一个状态下识别有人将发出警报声,一个状态下什么都不做。系统初始状态为非工作状态。
下面就来看看其状态接口,代码如下:
package cn.lut.curiezhang.designpattern.state;
//报警设备状态接口
public interface IAlarmDeviceStatus {
public void detectedPerson();
}
有了接口,来实现报警设备处于工作状态,识别有人将发出警报声,代码如下:
package cn.lut.curiezhang.designpattern.state;
public class AlarmDeviceActivation implements IAlarmDeviceStatus {
@Override
public void detectedPerson() {
System.out.println("响铃...");
}
}
类似地,非工作状态的代码如下:
package cn.lut.curiezhang.designpattern.state;
public class AlarmDeviceInactivation implements IAlarmDeviceStatus {
@Override
public void detectedPerson() {
System.out.println("无警报。");
}
}
有了状态类,建立情境——报警系统来实现状态的转换,代码如下:
package cn.lut.curiezhang.designpattern.state;
public class AlarmSystem {
IAlarmDeviceStatus activate = new AlarmDeviceActivation();
IAlarmDeviceStatus inactivate = new AlarmDeviceInactivation();
IAlarmDeviceStatus status = null;
public AlarmSystem() {
status = inactivate;
}
public void activate() {
changeStatus(activate);
}
public void inactivate() {
changeStatus(inactivate);
}
public void detectedPerson() {
status.detectedPerson();
}
private void changeStatus(IAlarmDeviceStatus status) {
this.status = status;
}
}
现在就可以进行报警系统的测试了,代码如下:
package cn.lut.curiezhang.designpattern.state;
/**
* Client
*
*/
public class Client
{
public static void main( String[] args )
{
AlarmSystem alarmSystem = new AlarmSystem();
System.out.println("设备非工作状态...");
System.out.println("有人时容易形成干扰。");
alarmSystem.inactivate();
System.out.println("识别有人");
alarmSystem.detectedPerson();
System.out.println("下班");
System.out.println("报警设备处于工作状态...");
alarmSystem.activate();
System.out.println("识别有人");
alarmSystem.detectedPerson();
}
}
代码执行结果如下图所示:
代码实现就是这样的,下面来看看上面设计模式的基本结构,通过类图了解其基本构成,如下图所示:
了解了其基本结构,就需要搞清楚这些类是怎么样来完成交互的,也就是这些对象之间是如何协作的?就通过顺序图来了解其工作过程,如下图所示:
请注意其交互过程。