设计模式之状态模式


设计模式是经验总结,是学习软件设计的有效方法,因此,了解和理解现有的设计模式,是提高软件设计的有效途径之一,这里将介绍相关的设计模式,并通过示例了理解其用法。

状态模式(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();
    }
}

代码执行结果如下图所示:
结果
代码实现就是这样的,下面来看看上面设计模式的基本结构,通过类图了解其基本构成,如下图所示:
类图
了解了其基本结构,就需要搞清楚这些类是怎么样来完成交互的,也就是这些对象之间是如何协作的?就通过顺序图来了解其工作过程,如下图所示:
顺序图
请注意其交互过程。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值