策略模式和状态模式是比较相同的两种设计模式,都是处理对象处在多种环境下的问题。策略模式是适用对象的某个逻辑有多种解决方案的场景,状态模式是适用一个对象内部有多种状态的场景。策略模式注重的是一个问题有多种解决方案,而状态模式注重的是对象内部自身的多种状态。举个例子:我们在对一组数字进行排序的时候,有多种排序算法供使用,比如冒泡、快排等,这时,排序是需要解决的问题,而具体的排序算法则是解决问题的策略,显然一个问题对应多种策略。再比如小汽车,在P档时,踩油门,车子不会移动;在D档时,踩油门,车子会向前走;在R档时,踩油门,车子会向后倒。这就是一种典型多状态模型。车子在不同的状态下同一种动作有不同表现。
定义
策略模式
定义一系列的算法(策略),并将每一个算法(策略)封装起来,并且这些算法还可以相互替换,策略模式让算法独立于调用者,并可以发生变化
状态模式
一个对象的内在状态发生改变时可以改变其行为
场景
策略模式
- 针对同一个问题,在仅仅是具体行为有差别的前提下,有多种解决方式
- 需要封装多种同一类型的操作时
- 出现同一个抽象类有多个子类,而又需要使用条件判断语句或者分支判断语句来选择具体的子类时
状态模式
- 一个对象的行为取决于它的状态
- 含有大量与对象状态有关的条件判断语句,可以考虑使用状态模式
特点
共同特点
- 可以解决繁杂的条件判断和分支判断逻辑,减少代码中条件判断和分支判断代码(if…else)
- 都是解决对象适配多场景的问题
- 极强的扩展性
策略模式
- 侧重支持多种方式解决对象的某个问题
状态模式
- 侧重解决对象本身在多种状态下的不同表现问题
实现
策略模式
具备三个要素
- 抽象策略类接口
- 抽象策略执行方法
- 装配策略的方法
用策略模式来接解决前面提到的排序算法。
首先声明排序策略接口
public interface ISortStrategy {
void sort(int[] nums);
}
分别创建快速排序和堆排序的策略实现类
/**
* 快速排序策略实现类
*/
public class QuickSortStrategy implements ISortStrategy {
@Override public void sort(int[] nums) {
// 快排代码
}
}
/**
* 堆排序策略实现类
*/
public class HeapSortStrategy implements ISortStrategy {
@Override public void sort(int[] nums) {
// 堆排序代码
}
}
然后创建排序的行为类
public class Sort {
private ISortStrategy mStrategy;
public void setStrategy(ISortStrategy strategy) {
mStrategy = strategy;
}
public void sort(int[] toSort) {
// TODO: 2020-02-25 检测是否有默认策略
mStrategy.sort(toSort);
}
}
该类中持有一个策略接口类型的成员变量,通过setStrategy
方法装配策略,在sort
方法中实际调用的是策略实现类的排序方法
public static void action(int[] nums) {
Sort sort = new Sort();
sort.setStrategy(new QuickSortStrategy());
sort.sort(nums);
}
使用起来也很简单,首先装配策略,然后调用对象的行为方法即可。
状态模式
该模式至少具备:
- 抽象状态接口
- 抽象状态中执行动作的抽象方法
- 设置对象状态的方法
我们通过状态模式解决前面提到的小汽车的问题。假设小汽车有三种状态。P档、R档、D档。分别对应一种操作。加速。
首先创建状态接口,里面有一个加速的抽象方法
public interface ICarState {
void speedUp();
}
然后创建三个实现类,分别代表P档状态、R档状态、D档状态
public class PackingState implements ICarState {
@Override public void speedUp() {
System.out.println("当前处于P档,车子无法移动");
}
}
public class ReverseState implements ICarState {
@Override public void speedUp() {
System.out.println("当前处于R档,倒车");
}
}
public class DriveState implements ICarState {
@Override public void speedUp() {
System.out.println("当前处于D档,车子前进");
}
}
最后是汽车类
public class Car {
private ICarState mState;
public void setState(ICarState state) {
this.mState = state;
}
public void sppedUp(){
// TODO: 2020-02-25 添加默认状态
mState.speedUp();
}
}
当汽车踩油门时,调用speedUp
方法,方法体内部会调用mState
的speedUp
方法。不同的状态表现的结果也不一样。
public void main() {
Car car = new Car();
car.setState(new PackingState());
car.sppedUp();
}
总结
策略模式和状态模式都是针对对象在多场景下一种设计模式。从上面的分析中可以看出,策略模式体现的是对象外部不同策略得到相同的结果,而状态模式体现的是对象内部不同的状态在同一种操作时表现出不同的结果。
两种设计模式都是为了解决代码中复杂的分支判断和条件判断语句。降低执行逻辑和执行对象间的耦合度,提高了扩展性。
当然,因为需要创建额外的策略实现类或者状态类,会消耗更多的内存空间。