策略模式 vs 状态模式

自从知道了策略模式和状态模式这两个行为类的设计模式后,就一直觉得这两个模式有点难以区分。不仅 UML 类图看起来没什么区别,就连具体实现也是非常相似。经过一段时间研究,稍微有了一点理解。

策略模式和状态模式都是消除含有大量 if…else 或 switch…case 这类硬编码结构的良策,虽然不是所有硬编码结构都可以用这两种模式来消除。根据我的理解,可以从其应用场景方面来区分两个模式。

从关注焦点区分

策略模式关注的焦点在于具体的某一个行为,准确的说是某一行为的具体执行过程。一般来说,即使拥有多种不同的执行过程,但是执行的结果是相同的。就比如拿到一串数字进行排序,排序是一个行为,可以理解为类中的一个方法,这个方法是抽象的。而不同的排序算法就是对排序行为的不同实现。不同的排序算法所耗费的内存空间和时间都不相同,但是最终的排序结果都是相同的。这应该是策略模式的典型应用场景。

状态模式关注的焦点在于内部状态的改变而引起的行为的变化。即在不同的状体下,某一个行为的执行是不尽相同的。不仅是行为过程不同,甚至是结果也会改变。比如在一个电商网站的某个商品页面,点击购买。如果用户是已登录状态,那么就会跳转至订单结算页面;但如果是未登录状态,就会跳转到登录页面要求用户先登录。

从外部干涉区分

从干涉方式来看,策略模式中具体行为策略的改变是由调用方主动指定的,除此之外,没有其他因素会让具体的执行策略发生改变。也就是对于某一个 context 对象而言,只有一个最合适的策略对象。也就是当我们指定了某个具体的排序算法后,如果不主动重新指定,那么以后就会一直使用该算法进行排序,不会发生改变。context 内部策略的改变对于调用方是透明的,因为策略的改变是由调用方发起的。

而状态模式中状态对象的改变是不需要调用方主动干涉的,根据 context 对象相关属性的变化,就会引起 context 内部 state 对象的变化。而与状态相关的方法都依赖于具体的状态对象。并且在执行了相关方法后,状态会自动发生改变。而这些状态的改变对于调用方是隐藏的,调用只是想调用某个方法,但是这个方法在不同状态的执行结果,调用方是无法预测的。就好像上面商城的案例中,当你点击购买按钮的时候,你并不知道是否一定会跳转到订单结算付款页面。

总结

可以说,策略模式封装的是行为,而状态模式封装的是变化。尽管这么说,但事实上策略模式与状态模式在很多情况下都是可以互相转化的,具体应该使用何种模式,就要从上面的两个方面尽心分析,能够看得出明显状态变化的,当热要用状态模式;如果只是选择一个合适的具体执行方案,那么显然策略模式更为适合,毕竟状态模式由于牵涉到状态的变化和转移方向,是要比策略模式略微复杂的,这里的复杂并不是指代码难以理解,而是从设计模式的角度来说明类的结构。