七、状态设计模式

1. 状态设计模式介绍

很多情况下,一个对象的行为取决于它的一个或者多个变化的属性,这些属性我们称之为状态,这个对象称为状态对象。对于状态对象而言,它的行为依赖于它的状态。

举个例子: 我们买火车票,只有我们买票了之后,才会有退票这个选项。没有买票则没有退票的选项。所以说我们退票的行为依赖于我们已经买票了这个”状态”。

状态模式和策略模式的结构很相似,但是它们的目的和本质上却不是一样的。

状态模式是平行的,不可替换的;策略模式是彼此独立的,可相互替换的。怎么理解这句话呢?

举个例子,策略设计模式就好比我们到达一个目的地有多种策略,坐汽车,坐火车,坐飞机。这三个方案之间是相互独立,互不影响的,并且是相互替换的。
状态模式拿刚刚那个买票的例子,已经买票和退票这两个行为是平行的,它们之间是有联系的。并且这两个状态是不可以相互替换的。

2. 状态设计模式使用场景

  • 一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为。
  • 代码中包含大量与状态对象有关的条件语句。(if-else)

3. 状态设计模式的UML类图

状态模式UML类图

4. 状态设计模式的实现

情景如下: 我们都有买过火车票的经历,没有下单之前,查询订单信息,退款功能是没有的。下单之后,下单是没有的,因为不可以下同一单(单号相同)。

  • 如果我们采用传统的if-else,代码如下:
public class Client {
            private final static int BEFORE_ORDERED = 0;
            private final static int AFTER_ORDERED = 1;

            private int mState = 0;

            public static void main(String[] args) {
                Client client = new Client();
                //下单之前
                client.setOrderState(BEFORE_ORDERED);
                client.order();
                client.queryInfo();
                client.refund();

                System.out.println("--------");

                client.setOrderState(AFTER_ORDERED);
                client.order();
                client.queryInfo();
                client.refund();

            }

            //设置订单状态
            public void setOrderState(int orderState) {
                this.mState = orderState;
            }

            //下单
            public void order() {
                if (mState == BEFORE_ORDERED) {
                    System.out.println("下单了");
                }
            }

            //查询订单详情
            public void queryInfo() {
                if (mState == AFTER_ORDERED) {
                    System.out.println("订单详情");
                }
            }

            //退款
            public void refund() {
                if (mState == AFTER_ORDERED) {
                    System.out.println("退款了");
                }
            }
        }

采用传统的if-else,我们发现每次都要变换写if-else的条件,稍有不慎就可能写错。如果条件更为复杂,代码将更加冗余繁杂。

  • 下面我们来看看采用状态设计模式之后的代码:

    包结构如下:

    买票例子包结构

(1) 首先定义一个接订单状态的接口:

public interface OrderState {

        //下单
        public void order();

        //查看订单状态
        public void queryInfo();

        //退款
        public void refund();
    }

(2)接下来定义“下单之前”的状态类和下单之后的状态类,两个都实现这个接口
下单之前的状态类:

public class BeforeOrdered implements OrderState {
        @Override
        public void order() {
            System.out.println("下单了");
        }

        @Override
        public void queryInfo() {
            //无法查询到任何信息,当前还没有订单
        }

        @Override
        public void refund() {
            //无法退款,当前还没有任何订单
        }
    }

下单之前只有order()方法实现了具体方法,因为其他两个再当前状态下无法执行。

下单之后的状态类:

public class AfterOrdered implements OrderState {
        @Override
        public void order() {
            //已经下单后,不能重复下同一单
        }

        @Override
        public void queryInfo() {
            System.out.println("正在查询订单信息");
        }

        @Override
        public void refund() {
            System.out.println("正在退款");
        }
    }

下单后的状态类中,实现了后面两个方法,因为在“下单后”的状态下,不能重复下同一个订单,所以order()方法没有实现。

(3) 接下来我们来定义一个状态控制类:

public class OrderStateController implements OrderState{

        private OrderState orderState;

        public void setOrderState(OrderState orderState) {
            this.orderState = orderState;
        }

        @Override
        public void order() {
            orderState.order();
        }

        @Override
        public void queryInfo() {
            orderState.queryInfo();
        }

        @Override
        public void refund() {
            orderState.refund();
        }
    }

在OrderStateController这个类中,通过 setOrderState()方法设置不同的状态。
然后实现OrderState接口中的三个方法,而具体调用的是通过setOrderState()设置的状态类里面对应的方法。

(4) 测试类:

public class Client {
        public static void main(String[] args) {

            OrderStateController orderStateController = new OrderStateController();

            //状态:下单之前
            orderStateController.setOrderState(new BeforeOrdered());
            //下单之前下单
            orderStateController.order();
            //下单之前查询
            orderStateController.queryInfo();
            //下单之前退款
            orderStateController.refund();

            System.out.println("---------------");

            //改变状态,下单了
            orderStateController.setOrderState(new AfterOrdered());
            //下单之后,下单
            orderStateController.order();
            //下单之后查询
            orderStateController.queryInfo();
            //下单之后退款
            orderStateController.refund();
        }
    }

结果如下:

买票例子结果

5. 状态设计模式在Android源码中

在Android源码中,WIFI管理是一个典型的状态模式。

当我们点击扫描WIFI时,不同的状态对于扫描WIFI这个请求的处理方式是不一样的。

  • 在初始状态下: 扫描请求直接被忽略。
  • 在驱动加载状态下: WIFI扫描请求被添加到延迟处理的消息队列。
  • 在驱动加载完成状态下: 扫描WIFI的请求直接被处理。

6. 状态设计模式在Android开发中

状态模式在Android中的开发,其实就是在Java中开发。一般只要用到if-else的地方,都能够用到状态模式。

比如登录和注销两种状态模式下,相同的操作会有不同的结果。

比如我们打开一个新安装的应用,注销状态下,评论操作直接跳转到登录界面。而在登录状态下,就可以跳转评论的操作界面。

其实不论是在Android下还是Java,状态模式的关键点在于不同的状态下对于同一行为有不同的响应,这其实就是一个将if-else用多态来实现的一个具体实例。

7. 总结

  • 优点:
    • 将特定状态下的行为封装,是不同状态下的行为独立起来,减少相互依赖。
    • 减少多余繁琐的状态判断。
  • 缺点:
    • 使类的数目增加。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值