Java设计模式之行为型:状态模式

Java设计模式之行为型:状态模式

背景:

        介绍状态模式前,我们先看这样一个实例:公司力排万难终于获得某个酒店的系统开发项目,并且最终落到了你的头上。下图是他们系统的主要工作:

Java设计模式之行为型:状态模式

        当第一眼看到这个系统时你就看出这是一个状态图,每个框都代表了房间的状态,箭头表示房间状态的转换。分析如下:房间有三个状态:空闲、已预订、已入住,状态与状态之间可以根据客户的动作来进行转换,定义每个状态的值。

    public static final int FREEMTIME_STATE = 0;  //空闲状态
    public static final int BOOKED_STATE = 1;     //已预订状态
    public static final int CHECKIN_STATE = 2;    //入住状态

    int state = FREEMTIME_STATE;     //初始状态

        通过客户的动作将每个状态整合起来,实现这个功能最简单的方式肯定是 if…else 啦!所以这里我们就通过动作将所有的状态全面整合起来。分析得这里有四个动作:预订、入住、退订、退房。如下:

    /**
     * @desc 预订
     */
    public void bookRoom(){
        if(state == FREEMTIME_STATE){   //空闲可预订
            if(count > 0){
                System.out.println("空闲房间,完成预订...");
                state =  BOOKED_STATE;     //改变状态:已预订
                count --;
                //房间预订完了,提示客户没有房源了
                if(count == 0){
                    System.out.println("不好意思,房间已经预订完,欢迎您下次光临...");
                }
            }
            else{
                System.out.println("不好意思,已经没有房间了....");
            }
        }
        else if(state == BOOKED_STATE){
            System.out.println("该房间已经被预订了...");
        }
        else if(state == CHECKIN_STATE){
            System.out.println("该房间已经有人入住了...");
        }
    }
    
    /**
     * @desc 入住
     */
    public void checkInRoom(){
        if(state == FREEMTIME_STATE){
            if(count > 0){
                System.out.println("空闲房间,入住...");
                state =  CHECKIN_STATE;     //改变状态:已预订
                count --;
                //房间预订完了,提示客户没有房源了
                if(count == 0){
                    System.out.println("不好意思,房间已经预订完,欢迎您下次光临...");
                }
            }
            else{
                System.out.println("不好意思,已经没有房间了....");
            }
            
        }
        else if(state == BOOKED_STATE){
            if("如果该房间是您预订的"){
                System.out.println("入住....");
                state = CHECKIN_STATE;
            }
            else{
                System.out.println("您没有预订该房间,请先预订...");
            }
        }
        else if(state == CHECKIN_STATE){
            System.out.println("该房间已经入住了...");
        }
    }
    
    /**
     * @desc 退订
     */
    public void unsubscribeRoom(){
        if(state == FREEMTIME_STATE){}
        else if(state == CHECKIN_STATE){}
        else if(state == BOOKED_STATE){
            System.out.println("已退订房间...");
            state = FREEMTIME_STATE;
            count ++;
        }
    }
    
    /**
     * @desc 退房
     */
    public void checkOutRoom(){
        if(state == FREEMTIME_STATE){}
        else if(state == BOOKED_STATE){}
        else if(state == CHECKIN_STATE){
            System.out.println("已退房..");
            state = FREEMTIME_STATE;
            count++;
        }
    }

        正当你完成这个 “复杂” 的 if..else 时,客户增加需求说需要将某些房间保留下来以作为备用(standbyState),于是悲剧了,因为你发现要在所有的操作里都要判断该房间是否为备用房间。当你老大经过你身边的时候发现你正在纠结怎么改的时候,你老大就问你为什么不换一个角度思考以状态为原子来改变它的行为,而不是通过行为来改变状态呢?于是你就学到了状态模式。

一、什么是状态模式:

        状态模式,就是允许对象在内部状态发生改变时改变它的行为,对象看起来就好像修改了它的类,也就是说以状态为原子来改变它的行为,而不是通过行为来改变状态。

        当对象的行为取决于它的属性时,我们称这些属性为状态,那该对象就称为状态对象。对于状态对象而言,它的行为依赖于它的状态,比如要预订房间,只有当该房间空闲时才能预订,想入住该房间也只有当你预订了该房间或者该房间为空闲时。对于这样的一个对象,当它的外部事件产生互动的时候,其内部状态就会发生变化,从而使得他的行为也随之发生变化。

        

二、UML结构图:

Java设计模式之行为型:状态模式

  • Context:环境类,可以包括一些内部状态
  • State:抽象状态类,定义了所有具体状态的共同接口,任何状态都需要实现这个接口,从而实现状态间的互相转换
  • ConcreteState:具体状态类,处理来自 Context 的请求,每一个 ConcreteState 都提供了它对自己请求的实现,所以,当 Context 改变状态时行为也会跟着改变

从上面的UML结构图我们可以看出状态模式的优点在于:

(1)封装了转换规则,允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块

(2)将所有与状态有关的行为放到一个类中,可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。 

但是状态模式的缺点在于:

(1)需要在枚举状态之前需要确定状态种类

(2)会导致增加系统类和对象的个数。

(3)对 “开闭原则” 的支持并不友好,新增状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态;而且修改某个状态类的行为也需修改对应类的源代码。

所以状态模式适用于:代码中包含大量与对象状态有关的条件语句,以及对象的行为依赖于它的状态,并且可以根据它的状态改变而改变它的相关行为。

策略模式和状态模式比较:策略模式和状态模式的结构几乎完全一致,但是它们的目的和本质完全不一样。策略模式是围绕可以互换的算法来创建业务的,而状态模式是通过改变对象内部的状态来帮助对象控制自己行为的。前者行为是彼此独立、可以相互替换的,后者行为是不可以相互替换的。

三、代码实现:

以前面的酒店的案例进行代码实现,对于该实例的UML图如下:

Java设计模式之行为型:状态模式

首先是状态接口:State

public interface State {
    /**
     * @desc 预订房间
     */
    public void bookRoom();
    
    /**
     * @desc 退订房间
     */
    public void unsubscribeRoom();
    
    /**
     * @desc 入住
     */
    public void checkInRoom();
    
    /**
     * @desc 退房
     */
    public void checkOutRoom();
    
}

然后是房间类:

public class Room {
    /*
     * 房间的三个状态
     */
    State freeTimeState;    //空闲状态
    State checkInState;     //入住状态
    State bookedState;      //预订状态
 
    State state ;  
    
    public Room(){
        freeTimeState = new FreeTimeState(this);
        checkInState = new CheckInState(this);
        bookedState = new BookedState(this);
        
        state = freeTimeState ;  //初始状态为空闲
    }
    
    /**
     * @desc 预订房间
     */
    public void bookRoom(){
        state.bookRoom();
    }
    
    /**
     * @desc 退订房间
     */
    public void unsubscribeRoom(){
        state.unsubscribeRoom();
    }
    
    /**
     * @desc 入住
     */
    public void checkInRoom(){
        state.checkInRoom();
    }
    
    /**
     * @desc 退房
     */
    public void checkOutRoom(){
        state.checkOutRoom();
    }
 
    public String toString(){
        return "该房间的状态是:"+getState().getClass().getName();
    }
    
    /*
     * getter和setter方法
     */
    public State getFreeTimeState() {
        return freeTimeState;
    }
 
    public void setFreeTimeState(State freeTimeState) {
        this.freeTimeState = freeTimeState;
    }
 
    public State getCheckInState() {
        return checkInState;
    }
 
    public void setCheckInState(State checkInState) {
        this.checkInState = checkInState;
    }
 
    public State getBookedState() {
        return bookedState;
    }
 
    public void setBookedState(State bookedState) {
        this.bookedState = bookedState;
    }
 
    public State getState() {
        return state;
    }
 
    public void setState(State state) {
        this.state = state;
    }
}

  然后是3个状态类,这个三个状态分别对于这:空闲、预订、入住。其中空闲可以完成预订和入住两个动作,预订可以完成入住和退订两个动作,入住可以退房。

/** 
 * @Description: 空闲状态只能预订和入住
 */
public class FreeTimeState implements State {
    
    Room hotelManagement;
    
    public FreeTimeState(Room hotelManagement){
        this.hotelManagement = hotelManagement;
    }
    
    
    public void bookRoom() {
        System.out.println("您已经成功预订了...");
        hotelManagement.setState(hotelManagement.getBookedState());   //状态变成已经预订
    }
 
    public void checkInRoom() {
        System.out.println("您已经成功入住了...");
        hotelManagement.setState(hotelManagement.getCheckInState());   //状态变成已经入住
    }
 
    public void checkOutRoom() {
        //不需要做操作
    }
 
    public void unsubscribeRoom() {
        //不需要做操作
    }
}
/** 
 * @Description: 入住状态房间只能退房
 */
public class BookedState implements State {
    Room hotelManagement;
    
    public BookedState(Room hotelManagement) {
        this.hotelManagement = hotelManagement;
    }
 
    public void bookRoom() {
        System.out.println("该房间已近给预定了...");
    }
 
    public void checkInRoom() {
        System.out.println("入住成功..."); 
        hotelManagement.setState(hotelManagement.getCheckInState());         //状态变成入住
    }
 
    public void checkOutRoom() {
        //不需要做操作
    }
 
    public void unsubscribeRoom() {
        System.out.println("退订成功,欢迎下次光临...");
        hotelManagement.setState(hotelManagement.getFreeTimeState());   //变成空闲状态
    }
}
/** 
 * @Description: 入住可以退房
 */
public class CheckInState implements State {
    Room hotelManagement;
    public CheckInState(Room hotelManagement) {
        this.hotelManagement = hotelManagement;
    }
 
    public void bookRoom() {
        System.out.println("该房间已经入住了...");
    }
 
    public void checkInRoom() {
        System.out.println("该房间已经入住了...");
    }
 
    public void checkOutRoom() {
        System.out.println("退房成功....");
        hotelManagement.setState(hotelManagement.getFreeTimeState());     //状态变成空闲
    }
 
    public void unsubscribeRoom() {
        //不需要做操作
    }
}

最后是测试类:

public class Test {
    public static void main(String[] args) {
        //有3间房
        Room[] rooms = new Room[2];
        //初始化
        for(int i = 0 ; i < rooms.length ; i++){
            rooms[i] = new Room();
        }
        //第一间房
        rooms[0].bookRoom();    //预订
        rooms[0].checkInRoom();   //入住
        rooms[0].bookRoom();    //预订
        System.out.println(rooms[0]);
        System.out.println("---------------------------");
        
        //第二间房
        rooms[1].checkInRoom();
        rooms[1].bookRoom();
        rooms[1].checkOutRoom();
        rooms[1].bookRoom();
        System.out.println(rooms[1]);
    }
}

运行结果:

Java设计模式之行为型:状态模式


 设计模式系列文章:

Java设计模式之创建型:工厂模式详解(简单工厂+工厂方法+抽象工厂)

Java设计模式之创建型:建造者模式

Java设计模式之创建型:单例模式

Java设计模式之创建型:原型模式

Java设计模式之结构型:适配器模式

Java设计模式之结构型:装饰器模式

Java设计模式之结构型:代理模式

Java设计模式之结构型:桥接模式

Java设计模式之结构型:外观模式

Java设计模式之结构型:组合模式

Java设计模式之结构型:享元模式

Java设计模式之行为型:策略模式

Java设计模式之行为型:模板方法模式

Java设计模式之行为型:责任链模式

Java设计模式之行为型:观察者模式

Java设计模式之行为型:访问者模式

Java设计模式之行为型:中介者模式

Java设计模式之行为型:命令模式

Java设计模式之行为型:状态模式

Java设计模式之行为型:备忘录模式

Java设计模式之行为型:迭代器模式

Java设计模式之行为型:解释器模式


原博客链接:设计模式读书笔记—–状态模式_chenssy 的技术博客-CSDN博客

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/114638.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 设计模式 | 适配器模式及典型应用

    设计模式 | 适配器模式及典型应用适配器模式适配器模式(AdapterPattern):将一个接口转换成客户希望的另一个接口,使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)。适配器模式既可以作为类结构型模式,也可以作为对象结构型模式。在适配器模式中,我们通过增加一个新的适配器类来解决接口不兼容的问题,使得原本没有任何关系的类可以协同工作。根据适配器类与适配者类的关系不同,适配器模式可分为对象适配器和类适…

    2022年7月25日
    11
  • Java经典23种设计模式之创造型模式(一)

    Java经典23种设计模式之创造型模式(一)

    2022年1月22日
    36
  • JAVA设计模式之单例模式

    本文继续介绍23种设计模式系列之单例模式。概念:  java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例、饿汉式单例、登记式单例。  单例模式有以下特点:  1、单例类只能有一个实例。  2、单例类必须自己创建自己的唯一实例。  3、单例类必须给所有其他对象提供这一实例。  单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例…

    2022年3月11日
    39
  • Java内存管理-掌握类加载器的核心源码和设计模式(六)

    勿在流沙筑高台,出来混迟早要还的。做一个积极的人编码、改bug、提升自己我有一个乐园,面向编程,春暖花开!上一篇文章介绍了类加载器分类以及类加载器的双亲委派模型,让我们能够从整体上对类加载器有一个大致的认识,本文会深入到类加载器源码分析,了解类加载器ClassLoader中核心的源码,并且分析ClassLoader中的设计思想或者设计模式! 本文地图:一、ClassLoader核…

    2022年2月28日
    35
  • cglib动态代理实现原理_java设计模式之代理模式

    cglib动态代理实现原理_java设计模式之代理模式代理模式(ProxyPattern)是一种结构性模式。代理模式为一个对象提供了一个替身,以控制对这个对象的访问。即通过代理对象访问目标目标对象,可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。文章目录代理模式静态代理动态代理cglib代理应用

    2022年10月16日
    3
  • Java设计模式之结构型:代理模式

    Java设计模式之结构型:代理模式

    2021年10月4日
    35

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号