首页
学习
活动
专区
圈层
工具
发布

Java设计模式(十二)状态模式

这一阵都没有按时的更新文章了,倒不是因为工作特别忙,只是因为最近工作项目中涉及到很多新东西,比如Spring Security,CAS,包括Hadop和docker。所以闲余时间都在补充这些知识,本想聊一聊单点登录和Spring Security的,但是想着学的不深入,而且设计模式就剩下几篇文章了,先更新完再说吧

在前面我们已经说完了创建型设计模式和结构型设计模式,行为型设计模式还剩下7种没有说,这个周末看看能完成几篇吧,今天我们要说的是状态模式。

01

状态模式

状态模式,从名字中就可以看出这个模式的核心是状态,那么怎么解释状态模式呢?举一个很简单的例子,我们在考试的时候,成绩的好坏跟你的考试状态是有关系的,当我们状态不好的时候成绩会下滑,状态好的时候成绩会上升,这可以叫做一种模式(毕竟绝大多数的时候这个模式是没问题的)。

在Java中也是一样,类的行为是基于它的状态改变的,就叫做状态模式,这种类型的设计模式属于行为型模式。

这种模式有什么好处呢?我结合我最近项目来聊一下:在我公司的OA产品中,角色的定义是很重要的的,一个人可以有很多种角色,这个角色就可以当成人员的状态。比如:在Java中User就是一个人,Roles代表他的角色,在某一个模块中,他可能有管理这个模块的权限,也有可能没有权限,我们判断的依据就是Roles。为什么说我们通常是根据你的角色来判断你是否有权限,而不是根据你这个人判断。根据人和根据角色有什么不同?考虑一下,根据角色我们在设计表的时候,只需要把角色ID和模块ID(多对多)对应上就可以,而如果根据人和模块对应,一两个人好解决,三千人呢?每一个人你都要去定义他的模块权限吗?此外即使是相同的角色,也会有级别区分,这个时候就会更加复杂,而如果我们使用状态模式(指的是给人员加上角色),我们只需要给人分配角色(或者说分配状态)就可以了(一个系统中可能有上百的模块,但是角色往往只有十几个),不用每个人都去分配模块的权限。所以说状态模式能让我区分一些类的属性,进而控制他的权限。

上面的例子说到了权限,我们怎么要怎么实现呢?

首先我们来定义一个角色

代码语言:javascript
复制
class Roles {
    //角色级别
    private int level;

    public int getLevel() {
        return level;
    }

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

    public void mode1() {
        System.out.println("级别低返回个别人的数据");
    }

    public void mode2() {
        System.out.println("级别高返回所有人数据");
    }
}

这个角色中有级别的属性,我们根据这个级别来区分返回的数据。在项目中,我们的角色是没有级别的,当给人员赋予角色的同时,我们会给这个人员和角色同时加上级别。

角色有了,那肯定要有一个执行状态判断的类存在了:

代码语言:javascript
复制
//
class Context {
    private Roles state;

    public Context(Roles state) {
        this.state = state;
    }

    public Roles getState() {
        return state;
    }

    public void setState(Roles state) {
        this.state = state;
    }

    public void method() {
        if (state.getLevel() < 0) {
            state.mode1();
        } else if (state.getLevel() > 0) {
            state.mode2();
        }
    }
}

这个类就像是一个监督员一样,它判断你的状态是怎么样的,进而去让类执行不同的行为。我们调用看一下:

代码语言:javascript
复制
    public static void main(String[] args) {

        Roles roles = new Roles();
        Context context = new Context(roles);

        roles.setLevel(1);
        context.method();

        roles.setLevel(-1);
        context.method();
    }

看这个主函数我们可以这样想。系统运行起来的时候,Roles和Context已经建立了起来,这个时候有人登进系统了,登系统的时候,一些其他的代码根据登录的ID判断他的级别,然后set进去,当页面加载完的时候,权限对应的数据就展示到登录人的面前了。

优点: 1、封装了转换规则。 2、枚举可能的状态,在枚举状态之前需要确定状态种类。 3、将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。 4、允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块。 5、可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。

缺点: 1、状态模式的使用必然会增加系统类和对象的个数。 2、状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。 3、状态模式对"开闭原则"的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态,而且修改某个状态类的行为也需修改对应类的源代码。

使用场景: 1、行为随状态改变而改变的场景。 2、条件、分支语句的代替者。

注意事项:在行为受状态约束的时候使用状态模式,而且状态不超过 5 个。

这里扯一句别的,就是小程序最近在做测试和提问的功能,争取11月份能够发布一版,目前已经大概做了一个模型,还有待完善,说出来也是为了督促自己:即使很忙,我也要抽时间去学习一些新的东西(因为小程序和后台管理系统不光光是自己成果的展示,也是我自我磨练,夯实基础的一种途径,还望大家多多支持。题库和文章模块最近也会开始更新)。

下一篇
举报
领券