23【状态设计模式】


二十三、状态设计模式

23.1 状态设计模式简介

23.1.1 状态设计模式概述

状态设计模式(State Pattern):允许对象在内部状态发生改变时,改变他的行为,对象看起来好像修改了它的类;

状态模式中类的行为是由状态来决定的,在不同的状态下有不同的行为。其核心是让一个对象在其内部改变的时候,行为也随之改变。状态模式关注的核心点时将状态与行为进行绑定,不同的状态具备不同的行为

【场景举例】

状态模式在我们生活中比较常见

  • 例1:如某个社交网站中,普通用户的权限为发布文章、浏览文章、使用限定皮肤,而VIP用户可以发布付费文章、浏览付费资源、使用更加精美的皮肤;普通用户和VIP用户这就是两个状态,不同状态可以做的事情(行为)是不一样的;
  • 例2:在网站中,未登录的用户可以浏览文章、查看评论等,登录过后的用户权限更加多,还可以点赞文章、收藏文章、发布评论等;登录的用户和未登录的用户就是两个状态,不同状态可以做的事情(行为)是不一样的;

状态模式要实现的就是一个操作一个对象时,其内部自动发生状态改变,看起来好像是修改了其他类一样;

23.1.2 状态设计模式的UML类图

状态设计模式中主要有3个角色:

  • 1)环境角色(Context):也称为上下文,它定义了客户程序需要的接口,维护一个当前状态,并将与状态相关的操作委托给当前状态对象来处理。
  • 2)抽象状态角色(State):定义一个接口,用以封装环境对象中的特定状态所对应的行为。
  • 3)具体状态角色(ConcreteState):实现抽象状态所对应的行为。

在这里插入图片描述

23.2 状态设计模式的实现

【案例】

在网站中,未登录的用户可以浏览文章、查看评论等,登录过后的用户权限更加多,还可以点赞文章、收藏文章等;如果在未登录状态下点赞文章,一般网站会弹出登录框提醒用户登录,用户登录过后具备点赞文章、收藏文章等功能;

下面我们使用状态模式来实现上述案例;

  • 1)抽象状态:
package com.pattern.demo01;

/**
 * @author lscl
 * @version 1.0
 * @intro: 抽象状态
 */
public abstract class AbstractUserState {

    protected Context context;

    public void setContext(Context context) {
        this.context = context;
    }

    // 点赞操作
    public abstract void thumbup();

    // 收藏操作
    public abstract void favorite();
}
  • 2)登录状态(具体状态):
package com.pattern.demo01;

/**
 * @author lscl
 * @version 1.0
 * @intro: 具体状态
 */
public class LoginState extends AbstractUserState {
    @Override
    public void thumbup() {
        System.out.println("点赞成功!");
    }

    @Override
    public void favorite() {
        System.out.println("收藏成功!");
    }
}
  • 3)未登录状态(具体状态):
package com.pattern.demo01;

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class UnLoginState extends AbstractUserState {
    @Override
    public void thumbup() {
        toLogin();
        System.out.println("点赞成功!");
    }

    @Override
    public void favorite() {
        toLogin();
        System.out.println("收藏成功!");
    }

    private void toLogin(){
        System.out.println("欢迎来到登录页面!");
        System.out.println("登录成功....");

        // 将状态设置为登录状态
        this.context.setState(this.context.LOGIN_STATE);
    }
}
  • 4)上下文角色:
package com.pattern.demo01;

/**
 * @author lscl
 * @version 1.0
 * @intro: 上下文对象对具体的状态进行管理
 */
public class Context {

    // 登录的状态
    public static final AbstractUserState LOGIN_STATE = new LoginState();

    // 未登录的状态
    public static final AbstractUserState UNLOGIN_STATE = new UnLoginState();

    // 当前状态(默认为未登录)
    private AbstractUserState currentState = UNLOGIN_STATE;

    {
        // 初始化上下文
        LOGIN_STATE.setContext(this);
        UNLOGIN_STATE.setContext(this);
    }

    public void setState(AbstractUserState userState) {
        this.currentState = userState;
        this.currentState.setContext(this);
    }

    public void favorite() {
        // 调用当前状态进行收藏
        this.currentState.favorite();
    }

    public void thumbup() {
        // 调用当前状态进行点赞
        this.currentState.thumbup();
    }
}
  • 5)测试类:
package com.pattern.demo01;

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class Demo01 {
    public static void main(String[] args) {

        // 创建上下文对象,包含多种状态
        Context context=new Context();

        // 使用上下文中的默认状态进行操作,如果发现当前状态不具备操作的权限将会自动切换状态,给用户感觉换了一个类一样
        context.favorite();
        context.thumbup();
    }
}

23.3 状态设计模式的优缺点

  • 优点:
    • 1)将状态转换显示化:通常对象的状态都是通过赋值进行表现,不够直观。而使用状态类,当状态切换时,是以不同的类进行表示的,转换目的更加明确;
    • 2)状态类职责明确,且具备扩展性;符合单一职责原则
  • 缺点:
    • 1)类膨胀:如果一类事物具备过多的状态,则会造成类的数量过多
    • 2)虽然支持新增状态,这方面扩展性好;但是在新增状态时,需要修改原先状态切换部分的源码,否则状态也不能切换到新定义的状态,这方面扩展性差,不符合开闭原则;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

緑水長流*z

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

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

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

打赏作者

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

抵扣说明:

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

余额充值