我在另外一篇博客里声称:作技术的思路是优先“怎么用”、然后再“是什么”。然而这里,我却想讨论一下状态模式与策略模式“是什么”,以及它们之间的区别。
这并非打脸,而是我在通过长久的思考“怎么用”以后,终于明白了它们“是什么”。git
让我想明白的契机,是“如何实现状态机(固然,是有限肯定状态机)”这样一个问题。下图是一个简单的状态机:
github
我本来计划用这样一套类来实现这个状态机:
画好类图以后我发现,这是个典型的策略模式。可是从直觉上来看,状态模式才是状态机的自然盟友。所以我又尝试着画了一套状态模式的图:
编程
一眼看上起,这两张类图如出一辙。固然,仔细看看,必定能发现其中的区别。相同点会带来相同的优势,不一样之处造就了各自的缺点。安全
这两张类图彷佛通常无二:一个对外接口;若干个接口方法;一个基类;若干个子类;另外有一个工厂与之配合。
之因此有如此高的类似度,是由于这两种模式的基本思路都是同样的:对外提供一个抽象,对内扩展为不一样的实现。app
看起来,只有接口方法不一样:策略模式用一个接口方法来处理全部的状态迁移;而状态模式则用不一样方法来处理迁移到不一样状态时的动做。
这个看起来不起眼的区别,实际上表明了这两种模式大相径庭的“抽象”方式。策略模式将状态迁移的“操做”设计为抽象接口;而状态模式的抽象接口表明了“状态”自己。换句话说,策略模式是对行为的抽象,状态模式是对数据的抽象。ide
面向接口的设计和编程方式能够带来数不尽的有点:接口对内高内聚,对外低耦合;实现类内部高内聚,彼此之间低耦合;对新增实现类保持开放,对修改现有类尽可能封闭;等等等等。spa
用策略模式实现状态机,从代码还原到状态机时会遇到一些困难。在我实践过的代码中,团队成员都反应过这一点。用状态模式来作会更明白一些:由于状态模式同时封装了数据和行为,虽然也只是一个“片断”,但片断中包含的信息更多。
用状态模式实现,则会遇到实例化的问题。这是因为包含有数据,因此“状态”实例线程不安全。于是每次执行状态迁移操做时,系统都须要使用一个新的实例。固然,这个问题能够变通解决,可是相比自然只有行为、一般只须要单例实现的策略模式,这仍是算得上一个缺点的。线程