前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >设计模式第八讲-状态模式

设计模式第八讲-状态模式

作者头像
用户2825413
发布2019-07-16 10:53:09
3340
发布2019-07-16 10:53:09
举报
文章被收录于专栏:呆呆熊的技术路

简介

状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类当中,可以把复杂的判断逻辑简化.

一个复杂的业务中可能存在大量的 if else等逻辑条件判断,对于后期维护来说是非常危险和复杂的。而状态模式也是将与特定状态相关的行为局部化,并且将不同状态的行为分割开来.

状态模式可以消除大量的条件分支语句,内部通过状态转移,来减少之间的相互依赖

  • 思考: 策略模式、责任链模式和状态模式的区别是什么

场景设置

比如为某网盘会员产品开发,有以下常见场景:

会员等级

权限

普通用户

存储照片、文件

会员

极速下载、5T空间…

超级会员

小视频自动备份、音视频倍速播放…

简单实现

权限获取类

代码语言:javascript
复制
package design.pattern;

import java.util.ArrayList;

public class UserRule {

    /**
     * 等级 1普通用户 2会员 3超级会员
     */
    private Integer level = 1;

    /**
     * 权限容器
     */
    private ArrayList<String> ruleList = new ArrayList<String>() {
        {
            add("上传文件");
            add("下载文件");

        }
    };

    public UserRule(Integer level) {
        this.level = level;
    }

    /**
     * 获取权限列表
     *
     * @return
     */
    public ArrayList<String> getRuleList() {

        if (this.level == 2) {  //会员
            //todo 权限获取
            ruleList.add("极速下载");
            ruleList.add("5T空间");
        } else if (this.level == 3) { //超级会员
            //todo 权限获取
            ruleList.add("光速下载");
            ruleList.add("10T空间");
            ruleList.add("小视频自动备份");
            ruleList.add("音视频倍速播放");
        }

        return ruleList;
    }
}

客户端调用:

代码语言:javascript
复制
Integer requestLevel = 3;

UserRule userRule = new UserRule(requestLevel);

ArrayList<String> ruleList = userRule.getRuleList();

//打印权限
System.out.println("会员等级" + requestLevel + "权限列表:");
for (Object object : ruleList) {
    System.out.println(object);
}

output:

代码语言:javascript
复制
会员等级3权限列表:
上传文件
下载文件
光速下载
10T空间
小视频自动备份
音视频倍速播放
思考:

似乎看起来我们的代码足够简单,很好的满足了根据等级返回权限的需求

我们重点关注下获取权限列表的根据不同的条件分支,处理不同的todo 的业务逻辑,如果我们加入了更多的等级,更复杂的权限计算方式等等功能, 这个if else将会更加的庞大起来.


就在这时产品过来又给你提了个v2.0的需求.

  • 产品: 最近市场反馈说我们会员卖的不是很好,现在我们要加一点点功能。
  • 我: …
  • 产品: 就是再返回当前等级的时候,把下个等级将要获取到的权限信息也给他返回,让他看到,鼓励用户做任务或付费.
  • 我: 我们不是有个列表可以让他直接对比看么,为什么还要单独提示啊
  • 产品: 你是产品还是我是产品啊
  • 我: 心里默念《人人都是产品经理》

使用状态模式消息掉那些多余的if else (当然还有那个最新的需求)

我们发现如果再加上返回下个版本的权限,真的是够了,再过几天不一定又出什么需求,这个方法看起来都要崩溃了. 看来需要优化一下了。

状态模式UML图(和策略模式一样)

首先我们建立一个抽象类(核心作用方便子类约束和传递)

State.java

代码语言:javascript
复制
package design.pattern.Rules;

import design.pattern.UserRule;
import design.pattern.UserVo;

import java.util.ArrayList;

public abstract class State {

    /**
     * 用户对象
     */
    protected UserRule userRule;

    /**
     * 权限容器
     */
    protected ArrayList<String> ruleList = new ArrayList<String>() {
        {
            add("上传文件");
            add("下载文件");

        }
    };

    public State(UserRule userRule) {
        this.userRule = userRule;
    }

    public abstract ArrayList<String> getRuleList(UserVo userVo);

}

继承State.java状态类,实现各自的会员返回类

代码语言:javascript
复制
package design.pattern.Rules;

import design.pattern.UserRule;
import design.pattern.UserVo;

import java.util.ArrayList;

/**
 * 一类会员
 */
public class MemberOne extends State {

    public MemberOne(UserRule userRule) {
        super(userRule);
    }

    /**
     * 获取权限列表
     *
     * @return
     */
    public ArrayList<String> getRuleList(UserVo userVo) {

        //如果是一类会员(普通)
        if (userVo.getLevel() == 1) {
            return ruleList;
        } else {
            userRule.setState(new MemberTwo(userRule)); //设置下一级别类
            return userRule.getRuleList(userVo);  //获取下一个级别的详情
        }
    }
}

剩下的两个会员类

代码语言:javascript
复制
package design.pattern.Rules;

import design.pattern.UserRule;
import design.pattern.UserVo;

import java.util.ArrayList;

/**
 * 三类会员
 */
public class MemberTwo extends State {

    public MemberTwo(UserRule userRule) {
        super(userRule);
    }

    /**
     * 获取权限列表
     *
     * @return
     */
    public ArrayList<String> getRuleList(UserVo userVo) {

        if (userVo.getLevel() == 2) {
            ruleList.add("极速下载");
            ruleList.add("5T空间");
            return ruleList;
        }else{
            userRule.setState(new MemberThree(userRule));
            return userRule.getRuleList(userVo);
        }
    }
}
代码语言:javascript
复制
package design.pattern.Rules;

import design.pattern.UserRule;
import design.pattern.UserVo;

import java.util.ArrayList;

/**
 * 三类会员
 */
public class MemberThree extends State {

    public MemberThree(UserRule userRule) {
        super(userRule);
    }

    /**
     * 获取权限列表
     *
     * @return
     */
    public ArrayList<String> getRuleList(UserVo userVo) {

        //最高级
        ruleList.add("光速下载");
        ruleList.add("10T空间");
        ruleList.add("小视频自动备份");
        ruleList.add("音视频倍速播放");
        return ruleList;
    }
}

为了参数方便传递管理,我们在下面单独声明一个view object类.

UserRule.java (桥梁类)

代码语言:javascript
复制
package design.pattern;

import design.pattern.Rules.MemberOne;
import design.pattern.Rules.State;

import java.util.ArrayList;

public class UserRule {

    /**
     * 具体权限对象
     */
    private State currentRule;

    public UserRule() {
        currentRule = new MemberOne(this);
    }

    /**
     * 设置权限对象
     *
     * @param state
     */
    public void setState(State state) {
        this.currentRule = state;
    }


    public ArrayList<String> getRuleList(UserVo userVo) {
        return this.currentRule.getRuleList(userVo);
    }

}

userRule类为我们优化前充满了条件判断的类,对他进行了解耦合.可以理解为对内调用类,对外暴露类的桥梁类 userVo对象是我们的参数对象,这里主要用于等级判断. 如果不成立,则进行重新设置下一个处理规则类,并同样调用规则列表方法。

UserVo.java (参数类)

代码语言:javascript
复制
package design.pattern;

public class UserVo {

    private String name;

    private Integer level;

    public UserVo(String name, Integer level) {
        this.name = name;
        this.level = level;
    }

    public String getName() {
        return name;
    }

    public Integer getLevel() {
        return level;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setLevel(int level) {
        this.level = level;
    }
}

客户端调用:

代码语言:javascript
复制
UserVo userVo = new UserVo("小红", 1);

UserRule userRule = new UserRule();
ArrayList<String> ruleList = userRule.getRuleList(userVo);

//打印
System.out.println("用户" + userVo.getName() + "当前权限如下:");
for (Object object : ruleList) {
    System.out.println(object);
}

//他的下个权限可以获得
userVo.setLevel(userVo.getLevel() + 1);
ruleList = userRule.getRuleList(userVo);
System.out.println("用户" + userVo.getName() + "将要权限如下:");
for (Object object : ruleList) {
    System.out.println(object);
}

output:

代码语言:javascript
复制
用户小红当前权限如下:
上传文件
下载文件
用户小红将要权限如下:
上传文件
下载文件
极速下载
5T空间

核心代码:

代码语言:javascript
复制
if (userVo.getLevel() == 1) {
    return ruleList;
} else {
    userRule.setState(new MemberTwo(userRule)); //设置下一级别类
    return userRule.getRuleList(userVo);  //获取下一个级别的详情
}

思考这段代码存在的问题? 如何优化?

策略模式和状态模式区别在哪里?

策略模式与状态模式极其相似,但是二者有其内在的差别

  • 策略模式将具体策略类暴露出去,调用者需要具体明白每个策略的不同之处以便正确使用。
  • 状态模式状态的改变是由其内部条件来改变的,与外界无关,二者在思想上有本质区别.
代码语言:javascript
复制
userRule.setState(new MemberTwo(userRule));),


本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-01-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 呆呆熊的技术路 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 简介
  • 场景设置
  • 简单实现
    • 思考:
    • 使用状态模式消息掉那些多余的if else (当然还有那个最新的需求)
    • 状态模式UML图(和策略模式一样)
    • 核心代码:
    • 策略模式和状态模式区别在哪里?
    相关产品与服务
    容器服务
    腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档