设计模式是什么鬼(状态)

简介: 设计模式是什么鬼(状态)

状态State,指某事物所处的状况或形态,比如水的三态,零下会变成固态冰,常温会是液态水,100℃会蒸发成气态的水蒸气。


在这个地球生态系统中,水的总量并不会增加,也不会减少,只是随着温度的变化其分子间发生了稀松紧密的变化罢了,于是便有了不同的行为,比如流动、凝固、或是蒸腾,但对于其本质H2O分子对象并没有任何变化,变化的,只是其形态。



image.png


当然,事物的状态都是不同的,有的多有的少。物质基本三态,人的精神状态更是非常复杂多变的,喜怒哀乐,五味杂陈。更有趣的是,对于某些患有严重的精神分裂的病人来说,其精神状态更是变化无常,有些竟可以扮演几十种角色,随时间或境遇切换,一会变成精明聪颖的律师,一会是懦弱的失败者总是要自杀,一个境遇触发又是愤怒的杀人暴徒,这人格切换速度,丧心病狂到令人发指



image.png


言归正传,依旧老惯例,我们还是用极简主义阴阳二态来做药引子,想必每个人家里都有开关吧,其暴露出两个UI可操作接口(对接你的手指):开,关。很简单吧?


image.png


好我们来分析一下,首先得定义一个类吧,就叫它:Switcher好了,对外暴露两个方法:switchOn()以及switchOff(),以便用户调用,OK,开始我们的代码。


1public class Switcher {
 2    //false代表关,true代表开
 3    private boolean state = false;//初始状态是关
 4
 5    public void switchOn(){
 6        state = !state;
 7        System.out.println("OK...灯亮");
 8    }
 9
10    public void switchOff(){
11        state = !state;
12        System.out.println("OK...灯灭");
13    }
14}


完成了?没问题了?这也太简单了吧?当然说这个没问题是在前端UI壳子设计精妙的前提下,但这并不能代表我们的程序设计没问题。试想如果UI可以重复调用开或者关会出现什么情况?状态乱套了!这个设计是非常不可靠的,我们不能因为表面设计上的完美就忽略了后端代码功能的逻辑正确性,表里不一。这就是为什么我们做应用时不但要做好前端校验(用户体验),更要保证后端校验(功能正确性)不可缺失。


想明白了的话我们继续,现在改一下我们之前的设计,这里一定要加入针对当前状态的条件判断,也就是说,开的状态不能再开,关的状态不能再关!


1public class Switcher {
 2    //false代表关,true代表开
 3    boolean state = false;//初始状态是关
 4
 5    public void switchOn(){
 6        if(state == false){//当前是关状态
 7            state = true;
 8            System.out.println("OK...灯亮");
 9        }else{//当前是开状态
10            System.out.println("WARN!!!通电状态无需再开");
11        }
12    }
13
14    public void switchOff(){
15        if(state == true){//当前是开状态
16            state = false;
17            System.out.println("OK...灯灭");
18        }else{//当前是关状态
19            System.out.println("WARN!!!断电状态无需再关");
20        }
21    }
22}


我们可以看到这里加入了逻辑判断,如果重复开或者重复关的话是会告警的,当然这里也可以抛异常出去,我们就不搞那么复杂化了。那对于这样的设计没有问题吧?很显然,逻辑上是跑的通的,写个Client类测试一下。


public class Client {
    public static void main(String[] args) {
        Switcher s = new Switcher();
        s.switchOff();//WARN!!!断电状态无需再关
        s.switchOn();//OK...灯亮
        s.switchOff();//OK...灯灭
        s.switchOn();//OK...灯亮
        s.switchOn();//WARN!!!通电状态无需再开
    }
}


So far,不管熊孩子怎么开开关关都不会有问题了。可惜我还是要很遗憾地告诉你,这样的设计仍然是糟糕的。试想,如果状态不止一种,并且状态切换有及其复杂的逻辑,例如,之前那个精神病患者,或者汽车的自动挡。


image.png


如果按照这种设计的结果会是?码农一定要有一种打破砂锅问到底的精神,不撞南墙不回头,Lu起袖子马上干!我们写一小段代码来看看先。


1public class Car {
 2    //0:Park驻车档,1:Reverse倒退挡,
 3    //2:Neutral空挡,3:Drive前进档。
 4    String state = "P";//初始状态是P档
 5
 6    public void push(){//向上推档杆
 7        switch (state) {
 8        case "P"://驻车档状态
 9            System.out.println("WARN!!!到头了推不动了!");
10            break;
11        case "R"://倒挡状态
12            state = "P";
13            System.out.println("OK...切P档");
14            break;
15        case "N"://空档状态
16            System.out.println("OK...切R档");
17            break;
18        case "D"://前进档状态
19            System.out.println("OK...切N档");
20            break;
21        default:
22            break;
23        }
24    }
25
26    public void pull(){//向下拉档杆
27        //这里省略,逻辑同上类似
28    }
29}


不用多说什么了吧,这个是在作死了,那一大堆逻辑判断写在宿主类里会越来越像蜘蛛网!我们必须想方设法把这个设计给模块化,把状态模块给独立出来!还记得我们曾经讲过的设计模式是什么鬼(策略)吧,算法策略被抽离出来,这里举一反三,把状态也给抽离出来,好了办法有了,我们忘掉自动挡,继续用我们大道至简的开关例子。


public interface State {
    public void switchOn(Switcher switcher);//开
    public void switchOff(Switcher switcher);//关
}


以上我们首先了定义一个状态State接口,两个方法开与关,注意这里与策略模式不同的是,我们为了与宿主Switcher对接所以把它作为参数传入。然后是开状态与关状态的实现。


1public class On implements State {
 2    @Override
 3    public void switchOn(Switcher switcher) {
 4        System.out.println("WARN!!!通电状态无需再开");
 5        return;
 6    }
 7
 8    @Override
 9    public void switchOff(Switcher switcher) {
10        switcher.setState(new Off());
11        System.out.println("OK...灯灭");
12    }
13}
1public class Off implements State {
 2    @Override
 3    public void switchOn(Switcher switcher) {
 4        switcher.setState(new On());
 5        System.out.println("OK...灯亮");
 6    }
 7
 8    @Override
 9    public void switchOff(Switcher switcher) {
10        System.out.println("WARN!!!断电状态无需再关");
11        return;
12    }
13}


显而易见,注意看第10行代码,开状态不能做开行为,只告警并返回,关状态反之亦然。而第4行代码则是合法的行为,所以可以进行状态切换并实施相应行为,也就是说,开状态可关,关状态可开。注意这里是把宿主对象传入进来用于切换其当前状态,亦或是调用宿主的具体功能方法(这里省略用打印输出代替),比如宿主里的一盏灯提供的方法。


至此,一切看起来非常优雅,我们已经成功的将状态从宿主中抽离了,最后再来看宿主开关类是什么样子。


1public class Switcher {
 2    //开关的初始状态设置为“关”
 3    private State state = new Off();
 4
 5    public State getState() {
 6        return state;
 7    }
 8
 9    public void setState(State state) {
10        this.state = state;
11    }
12
13    public void switchOn(){
14        state.switchOn(this);//这里调用的是当前状态的开方法
15    }
16
17    public void switchOff(){
18        state.switchOff(this);//这里调用的是当前状态的关方法
19    }
20}


甚至我们还可以给里面加一盏灯,像之前我们提到的那样,在State状态接口实现里去调用。


public class Switcher {
    //...之上代码略...
    private Lamp lamp;
    public void lampOn(){
        lamp.on();
    }
    public void lampOff(){
        lamp.off();
    }
}


看明白了吧?是不是很像策略模式?其实它就是策略的一个变种,只不过状态模式会更好的根据当前的状态去实施不同的行为,并且自主切换到另一个正确的状态,开变关,关变开。就好似电梯(虽然是嵌入式面向过程,这里只是举例),用户根本无法随意强制更改其状态以及行为,你让它上,它不一定马上就能上,否则会造成事故。电梯内部封装了多个状态以及对应的逻辑产生不同的行为,它会根据当前状态去自我调整并实施最优方案,以达到安全、高效的目的,这才是可靠的设计。



image.png


这些例子都很简单吧?确实很简单,但也不简单,例子本身简单,理解并不简单,所以大家一定要多分析思考,举一反三,最终才能融汇贯通,自由运用。光说不练是不行的,理论指导实践,实践加强理论,建议大家亲自去写一下上面的汽车自动挡例子。


推荐大而全的【后端技术精选】

相关文章
|
7月前
|
设计模式 算法 C++
从 C++ 优化状态机实现:结合设计模式的实用指南
从 C++ 优化状态机实现:结合设计模式的实用指南
545 1
|
设计模式 前端开发 数据安全/隐私保护
前端实现设计模式之状态模式
状态模式是一种行为型设计模式,用于在对象内部状态发生变化时改变其行为。状态模式将对象的行为封装在不同的状态类中,使得对象在不同的状态下可以有不同的行为。在前端开发中,状态模式常用于管理组件的状态和行为,以实现复杂的交互逻辑。本文将介绍状态模式的概念和应用,并提供具体的代码示例和解读。
165 0
|
7月前
|
设计模式 存储 前端开发
【设计模式】之调停者模式
调停者模式是一种有助于降低对象之间耦合度的设计模式。它通过引入一个调停者对象来集中处理一组对象之间的交互,使得代码更易于维护和扩展。在前端开发中,调停者模式可以应用于表单验证、消息订阅与发布、组件间通信等场景。尽管调停者模式可能会增加系统的复杂性,并且调停者对象可能变得庞大和复杂,但它仍然是一种有价值的设计模式,可以提高代码的可读性和可维护性。
67 0
【设计模式】之调停者模式
|
7月前
|
设计模式 数据处理 数据安全/隐私保护
如何将设计模式责任链模式运用到工作当中
如何将设计模式责任链模式运用到工作当中
|
7月前
|
设计模式
二十三种设计模式-解密状态模式:优雅地管理对象状态
二十三种设计模式-解密状态模式:优雅地管理对象状态
|
7月前
|
设计模式 监控 容器
设计模式-观察者模式(观察者模式的需求衍变过程详解,关于监听的理解)
设计模式-观察者模式(观察者模式的需求衍变过程详解,关于监听的理解)
|
设计模式 C++
二十三种设计模式:状态模式
状态模式,就是把所有的状态抽象成一个个具体的类,然后继承一个抽象状态类,在每一个状态类内封装对应状态的行为,符合开放封闭原则,当增加新的状态或减少状态时,只需修改关联的类即可。很适合多分支行为方法的处理,这里的多分支,当然是状态比较多的情况下,如果只有小于4个状态,个人认为还是分支处理简单些。
60 0
|
设计模式
状态设计模式解读
状态设计模式解读
|
设计模式 C#
设计模式——创建将模式总结
设计模式——创建将模式总结
73 0
|
设计模式 监控 uml
【对象行为模式】二十三天学会设计模式之观察者模式
【对象行为模式】二十三天学会设计模式之观察者模式
【对象行为模式】二十三天学会设计模式之观察者模式