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

栏目: 后端 · 发布时间: 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));),
复制代码

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

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

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

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

查看所有标签

猜你喜欢:

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

软件开发者路线图

软件开发者路线图

Dave H. Hoover、Adewale Oshineye / 王江平 / 机械工业出版社 / 2010年9月 / 35.00元

作为一名软件开发者,你在奋力推进自己的职业生涯吗?面对今天日新月异和不断拓展的技术,取得成功需要的不仅仅是技术专长。为了增强专业性,你还需要一些软技能以及高效的学习技能。本书的全部内容都是关于如何修炼这些技能的。两位作者Dave Hoover和Adewale Oshineye给出了数十种行为模式,来帮你提高主要的技能。 本书中的模式凝结了多年的调查研究、无数次的访谈以及来自O’Reilly在......一起来看看 《软件开发者路线图》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

在线进制转换器
在线进制转换器

各进制数互转换器

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具