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

栏目: 后端 · 发布时间: 5年前

内容简介:状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类当中,可以把复杂的判断逻辑简化.一个复杂的业务中可能存在大量的 if else等逻辑条件判断,对于后期维护来说是非常危险和复杂的。而状态模式也是将与特定状态相关的行为局部化,并且将不同状态的行为分割开来.可以消除大量的条件分支语句,内部通过状态转移,来减少之间的相互依赖

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

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

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

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

场景设置

比如你在参与百度网盘开发,有以下常见场景:

会员等级 权限
普通用户 存储照片、文件
会员 极速下载、5T空间...
超级会员 小视频自动备份、音视频倍速播放...

简单实现

权限获取类

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;
    }
}
复制代码

客户端调用:

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:

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

思考:

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

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

刚刚说完可能庞大起来,产品过来又给我提v2.0的需求.

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

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

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

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

State.java

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);

}
复制代码

第一步我们需要简单的参数对象(这里用view object)

UserVo.java

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;
    }
}
复制代码

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

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);  //获取下一个级别的详情
        }
    }
}

复制代码

UserRule.java (桥梁类)

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对象是我们的参数对象,这里主要用于等级判断. 如果不成立,则进行重新设置下一个处理规则类,并同样调用规则列表方法。

剩下的两个会员类

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);
        }
    }
}

复制代码
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类.

UserVo.java

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;
    }
}

复制代码

客户端调用:

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:

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

核心代码:

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

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

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

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

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

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

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

对比策略模式:策略模式详解

更多精彩内容请关注热情小宇公众号(呆呆熊一点通)

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

以上所述就是小编给大家介绍的《设计模式第八讲-状态模式》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Python高效开发实战——Django、Tornado、Flask、Twisted(第2版)

Python高效开发实战——Django、Tornado、Flask、Twisted(第2版)

刘长龙 / 电子工业出版社 / 2019-1 / 99

也许你听说过全栈工程师,他们善于设计系统架构,精通数据库建模、通用网络协议、后端并发处理、前端界面设计,在学术研究或工程项目上能独当一面。通过对Python 3及相关Web框架的学习和实践,你就可以成为这样的全能型人才。 《Python高效开发实战——Django、Tornado、Flask、Twisted(第2版)》分为3篇:上篇是Python基础,带领初学者实践Python开发环境,掌握......一起来看看 《Python高效开发实战——Django、Tornado、Flask、Twisted(第2版)》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

随机密码生成器
随机密码生成器

多种字符组合密码