软件设计模式学习(二十四)状态模式


状态模式用于解决系统中复杂对象的状态转换以及不一样状态下行为的封装问题java


模式动机

不少状况下,一个对象的行为取决于一个或多个动态变化的属性,这样的属性叫作状态。一个对象能够拥有多个状态,这些状态能够相互转换,当对象状态不一样时,其行为也有所差别。app

假设一我的就是对象,人根据心情不一样会有不少状态,好比开心和伤心,这两种状态能够相互转换。开心的人可能会忽然接到女友的分手电话,而后哭得稀里哗啦(醒醒!你哪来的女友?),过了一段时间后,又可能由于中了一百万彩票而欢呼雀跃。并且不一样状态下人的行为也不一样,有些人伤心时会经过运动、旅行、听音乐来缓解心情,而开心时则可能会唱歌、跳舞、请客吃饭等等。ide

再来考虑软件系统中的状况,如某酒店订房系统,能够将房间设计为一个类,房间对象有已预订、空闲、已入住等状况,这些状态之间能够相互转换,而且不一样状态的对象可能具备不一样的行为,如已预订或已入住的房间不能再接收其余顾客的预订,而空闲的房间能够接受预订。测试

在过去咱们遇到这种状况,可使用复杂的条件判断来进行状态判断和转换操做,这会致使代码的可维护性和灵活性降低,当出现新的状态时必须修改源代码,违反了开闭原则。在状态模式中,能够将对象状态从包含该状态的类中分离出来,作成一个个单独的状态类,如人的两种情绪能够设计成两个状态类:this

将开心与伤心两种情绪从“人”中分离出来,从而避免在“人”中进行状态转换和判断,将拥有状态的对象和状态对应的行为分离,这就是状态模式的动机。设计


模式定义

容许一个对象在其内部状态改变时改变它的行为,对象看起来彷佛修改了它的类。其别名为状态对象(Objects for States),状态模式是一种对象行为型模式。code

Allow an object to alter its behavior when its internal state changes. The object will appear to change its class.对象


模式结构与分析

咱们把拥有状态的对象称为环境类,也叫上下文类。再引入一个抽象状态类来专门表示对象的状态,对象的每一种具体状态类都继承该抽象类,不一样具体状态类实现不一样状态的行为,包括各类状态之间的转换。在环境类中维护一个抽象状态类 State 的实例,用来定义当前状态。blog

获得状态模式结构类图以下:继承

环境类中的 request() 方法处理业务逻辑,根据状态去调用对应的 handle() 方法,若是须要切换状态,还提供了 setState() 用于设置当前房间状态。若是咱们但愿执行操做后状态自动发生改变,那么咱们还须要在 State 中定义一个 Context 对象,实现一个双向依赖关系。

考虑前面提到的订房系统,若是不使用状态模式,可能就会存在以下代码:

if (state == "空闲") {
	if (预订房间) {
        预订操做;
        state = "已预订";
	} else if (住进房间) {
    	入住操做;
        state = "已入住";
    }
} else if(state == "已预订") {
	if (住进房间) {
        入住操做;
        state = "已入住";
	} else if (取消预订) {
    	取消操做;
        state = "空闲";
    }
}

上述代码须要作频繁且复杂的判断操做,可维护性不好。所以考虑使用状态模式将房间类的状态分离出来,将与每种状态有关的操做封装在独立的状态类中。

咱们来写一个完整的示例

环境类(Room)

public class Room {
	
    // 维护一个状态对象
    private State state;

    public Room() {
        // 默认为空闲状态
        this.state = new IdleState(this);
    }

    public State getState() {
        return state;
    }

    public void setState(State state) {
        this.state = state;
    }

    public void reserve() {
        state.reserve();
    }

    public void checkIn() {
        state.checkIn();
    }

    public void cancelReserve() {
        state.cancelReserve();
    }

    public void checkOut() {
        state.checkOut();
    }
}

抽象状态类(State)

public abstract class State {
	
    // 用于状态转换
    protected Room room;

    public State(Room room) {
        this.room = room;
    }

    public abstract void reserve();

    public abstract void checkIn();

    public abstract void cancelReserve();

    public abstract void checkOut();
}

具体状态类(IdleState)

public class IdleState extends State {

    public IdleState(Room room) {
        super(room);
    }

    @Override
    public void reserve() {
        System.out.println("房间预订成功");
        // 	切换状态
        room.setState(new ReservedState(room));
    }

    @Override
    public void checkIn() {
        System.out.println("房间入住成功");
        room.setState(new InhabitedState(room));
    }

    @Override
    public void cancelReserve() {
        System.out.println("没法取消预订,房间处于空闲状态");
    }

    @Override
    public void checkOut() {
        System.out.println("没法退房,房间处于空闲状态");
    }

}

具体状态类(ReservedState)

public class ReservedState extends State {

    public ReservedState(Room room) {
        super(room);
    }

    @Override
    public void reserve() {
        System.out.println("没法预订,房间处于已预订状态");
    }

    @Override
    public void checkIn() {
        System.out.println("房间入住成功");
        room.setState(new InhabitedState(room));
    }

    @Override
    public void cancelReserve() {
        System.out.println("取消预订成功");
        room.setState(new IdleState(room));
    }

    @Override
    public void checkOut() {
        System.out.println("没法退房,房间处于已预订状态");
    }
}

具体状态类(InhabitedState)

public class InhabitedState extends State {

    public InhabitedState(Room room) {
        super(room);
    }

    @Override
    public void reserve() {
        System.out.println("没法预订,房间处于入住状态");
    }

    @Override
    public void checkIn() {
        System.out.println("没法入住,房间处于入住状态");
    }

    @Override
    public void cancelReserve() {
        System.out.println("没法取消预订,房间处于入住状态");
    }

    @Override
    public void checkOut() {
        System.out.println("退房成功");
        room.setState(new IdleState(room));
    }
}

客户端测试类(Client)

public class Client {

    public static void main(String[] args) {

        Room room = new Room();
        room.cancelReserve();
        room.checkOut();
        room.reserve();
        System.out.println("--------------------------");
        room.reserve();
        room.checkOut();
        room.checkIn();
        System.out.println("--------------------------");
        room.reserve();
        room.checkIn();
        room.cancelReserve();
        room.checkOut();
    }
}

运行结果


模式优缺点

状态模式的优势:

  • 封装了转换规则,将不一样状态之间的转换状态封装在状态类中,避免了冗长的条件判断,提升了代码的可维护性
  • 将全部与某个规则有关的行为放到一个类,能够很方便地增长新的状态
  • 可让多个环境对象共享一个状态对象,从而减小系统中对象的个数

状态模式的缺点:

  • 增长了系统类和对象的个数
  • 结构较为复杂,使用不当将致使代码混乱
  • 对于能够切换状态的状态模式,增长新的状态类须要修改负责状态转换的代码
相关文章
相关标签/搜索