美文共赏

设计模式之——状态模式与策略模式

2019-10-07  本文已影响0人  leaf_shane

如果你的简历里出现了"设计模式"的字样,那么作为面试官的我几乎都会问到一个问题: "状态模式与策略模式有哪些区别"。很多人一脸懵,我就知道这次愉快的技术交流无疾而终了。可能对于很多人来说,策略模式比较熟悉,可什么是状态模式,好多人还是比较迷糊的。此篇专题,我们就来聊聊状态模式与策略模式。

第一部分 状态模式

考虑这样的一个场景:一个电梯,有四种操作:运行停止开门关门。每一种操作成功后,都对应着状态的切换。每一种状态,又可以随着操作,向另一种状态切换。但是状态与状态之间又不是随意切换的。如下表所示:

说得比较复杂,看一个状态机图

有箭头的,就是允许;没有箭头的,就不允许

Lift-State.png

1 错误示范

if - else真是个害人精,它让我们在实现功能的时候,不必过多地思考,很多没有研习过状态模式的同学也是可以轻松实现的——只不过没那么优美罢了。

Lift-Design.png

结论

从测试的结果可以看出,需求实现了,也没什么问题。但这是我们编写的简单代码,回过头再来审视一下Lift.java,我们做了大量的条件判断。同一个类当中的代码量又太多——如果状态不止4种,怎么办?如果状态与状态之间的切换,业务比较复杂,不能一两条代码就搞得定,又怎么办?

2 正确示范

在现实领域中,电梯状态,自然而然就是电梯的一个属性。然而在面向对象语言中,所谓万物皆对象,状态,自然也可以作为一个对象。既然状态可以作为对象,那么就可以利用多态来解决了。

Lift-Design-State-Pattern.png

结论

这种实现方式,电梯与电梯状态产生了双向依赖,属于一种紧耦合;电梯状态抽象父类,与电梯状态具体类又产生了双向依赖,属于一种紧耦合。理解起来有点绕,一条一条地说。

电梯具备一个电梯状态对象,当接收到操作请求时,电梯对象本身不做任何的判断和处理,而是交由状态对象处理。

当电梯状态接收到转换请求时,如果可以转换,那么我们想要得到的结果是:电梯的状态发生了变化。所以电梯状态需要向电梯对象发送"改变状态"的消息,那么电梯状态就需要知道,到底是哪一个电梯对象。所以电梯状态的转换操作,需要接收一个电梯对象的参数。

具体状态需要继承自抽象状态。

抽象状态定义了默认方法,其中的默认方法就是: 所有的操作,都是合法的。既然是合法的,就要向目标状态切换。因为使用了状态模式,状态是一个对象了,所以需要创建具体状态的对象,再把创建好的状态对象,发送给电梯。

Lift-Design-State-Pattern.png Lift-Sequence.png

3 状态模式总结

State-Pattern.png

第二部分 状态模式与策略模式

在上一篇文章《设计模式在RESTful当中的应用》当中,已经聊过策略模式,乍一看它们的类图,是很相似的:

State-Pattern.png Strategy-Pattern.png

策略模式与状态模式都把实际的行为,延迟到了子类,以此完成多态。同时,上下文(Context)面向的都是一个抽象类。(一些编程语言明确地区分了接口与抽象类,比如Java;而一些编程语言并没有明确地区分,比如C++。OOD本身与语言的关联是比较弱的,所以在OOP的时候,到底是面向接口还是抽象类,是需要酌情考虑的。)

状态模式与策略模式的区别

类结构相似,想要找出状态模式与策略模式的区别,就需要从它们的行为入手了

第三部分 总结

综上所述,策略模式实现起来比较简单,是真正利用了面向对象的多态技术,完成了算法的互换使用,并且既遵循了高内聚,又遵循了松耦合的设计原则。

而状态模式实现起来比较复杂,其亦是利用了面向对象的多态技术,完成状态与状态之间的过渡。虽然状态模式遵循了高内聚的设计原则,但却破坏了松耦合原则。

两者都是通过内聚,提升了灵活性可维护性可扩展性。但归根结底,两者的区别就在于:策略模式是松耦合、状态模式是紧耦合

打完收工

上一篇下一篇

猜你喜欢

热点阅读