设计模式之状态模式

状态模式的原理其实很简单:核心一个对象的行为取决于它的状态。也就是说如果一个对象的状态发生了变化,那么该对象的行为也要发生相应的改变。

虽然上面一句话说出了状态模式的核心所在,在这里还是要简单的分析下,算是加深理解!

这里写图片描述

按照上图以及面向对象的思维,状态模式设计到两种对象:
1、状态持有者对象(StateHolder)或者其他资料上所说的Context,本文为了方便说明也就沿袭Context这个惯例。
2、状态对象(States),一个状态持有者若干个状态。

然后就是定制状态切换的规则了,当然这个因需求而异,比如有的状态是在状态持有者内部自己切换的,是状态持有者主动进行状态切换以便进行下一个状态的操作。有的状态是由外部改变的,Context被动的接受状态的改变而进行相应的处理。网上各种介绍该模式的博文都是举一个简单的例子,本文也不免俗,就举个例子吧。

比如QQ,具有在线、离线、离开等状态,QQ在不同的状态会处理不同逻辑,比如在线状态下可以qq.sendMessage(),离线状态下提示登陆qq.goLogin(),离开状态下会给对方一个提醒qq.sendAlert()等。在这里QQ就是状态持有者,也就是状态模式中的Context对象。

非状态模式下的实现:

如果用非状态模式来处理的话,可能会有如下两种的代码的实现:

  private int state = 0;

    public void execute() {
        if (state == 0) {//离线状态
            goLogin();
        } else if (state == 1) {//在线状态
            sendMsg();
        } else if (state == 2) {//离开状态
            sendAlert();
        }
    }

    public void switchState(int newState) {
        state = newState;
    }

上面这种代码可扩展性不强,如果在增加许多状态的话,势必充斥着大量的if else 逻辑,随着状态的增多execute方法的代码量积聚增加。

状态模式实现的例子

设计一个QQState接口:

public interface QQState {
    void doAction(QQ qq);
}

实现离线、在线、离开状态的类:

//离线状态
public class OfflineState implements QQState {
    @Override
    public void doAction(QQ qq) {
        qq.goLogin();
    }
}

//在线状态
public class OnLineState implements QQState {
    @Override
    public void doAction(QQ qq) {
        qq.sendMsg();
    }
}

//离开状态
public class LeaveState implements QQState {
    @Override
    public void doAction(QQ qq) {
        qq.sendAlert();
    }
}

实现原理很简单,比如如果是离线状态,则qq这个状态持有者调用qq.goLoin()进行登陆操作。现在是时候看看状态持有者对象QQ的具体实现了:

public class QQ {
    //持有一个状态
    private QQState qqState;

    public QQ() {
        //初始化为离线状态
        qqState = new OfflineState();
    }

    public void switchState(QQState newState) {
        this.qqState = newState;
    }

    public void execeute() {
        qqState.doAction(this);
    }

    //在线状态下发送消息
    protected void sendMsg() {
        System.out.println("美女你好?");
    }

    //向对方发出消息
    protected void sendAlert() {
        System.out.println("我现在不在电脑旁");
    }

    //去登陆
    protected void goLogin() {
       System.out.println("已离线,请重新登陆");
    }
}

QQ 对象持有一个状态类的引用,且提供了switchState来切换状态信息。客户端代码如下:

 public static void main(String args[]) {
        QQ qq = new QQ();
        qq.execeute();
        System.out.println("--------------");
        //切换成线上状态
        qq.switchState(new OnLineState());
        qq.execeute();
        System.out.println("-------------");
        //切换成离开状态
        qq.switchState(new LeaveState());
        qq.execeute();
    }

运行效果如下:

 已离线,请重新登陆
-----------------------------
美女你好?
-----------------------------
我现在不在电脑旁

此时execute方法仅一行qqState.doAction(this)就可以搞定。当然了,如果状态多的话,也会创建大量的状态类,是的对象激增,这也是状态模式的缺点之一。

观察者模式的不同:
状态模式当状态发生改变时,响应变化的是状态持有者本身,而观察者模式则是被观察者自身发生改变时,通知不同的观察者对执行相应的改变。也就是说状态模式是外部或者内部的状态影响自身,而观察者模式则是影响别人(Observer)

至于与策略模式的区别,请参考博主的《设计模式之策略模式
到此为止,状态模式讲解完毕,如果不当之处欢迎批评指正。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

郭梧悠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值