状态模式
-
状态模式和策略模式:
- 策略模式的具体子类之间没有交互,而状态模式的具体子类直接有交互,为的是状态的切换。
- 策略模式的环境角色只是一个委托作用,负责算法的替换,而状态模式的环境角色不仅仅是委托的作用,还负责记录状态变化,与具体的状态类协作,共同完成状态类的切换。
- 策略模式的重点是为了解决内部算法如何改变的问题,也是将内部算法的改变对外界的影响降到最小,保证算法自由切换,而状态模式解决的是内在状态改变而引起的行为改变,作用点在于对象的状态,封装状态而暴露行为,状态改变带动行为改变。
-
定义:
允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。
状态模式用于解决系统中复杂对象的状态转换以及不同状态下行为的封装问题。当系统中某个对象存在多个状态,这些状态之间可以进行转换,而且对象在不同状态下行为不相同时可以使用状态模式。状态模式将一个对象的状态从该对象中分离出来,封装到专门的状态类中,使得对象状态可以灵活变化,对于客户端而言,无须关心对象状态的转换以及对象所处的当前状态,无论对于何种状态的对象,客户端都可以一致处理。
-
使用场景:
- 对象依赖于他的状态,并且可以根据不同的状态使用不同的行为。
- 代码中包含大量if else语句,并且带有对象的行为,使系统的可维护性和可拓展性变得很差,使用状态类可以有效的解决这些问题。
-
UML:
- Context:环境类又称为上下文类,它是拥有多种状态的对象。由于环境类的状态存在多样性且在不同状态下对象的行为有所不同,因此将状态独立出去形成单独的状态类。在环境类中维护一个抽象状态类State的实例,这个实例定义当前状态,在具体实现时,它是一个State子类的对象。
- State:它用于定义一个接口以封装与环境类的一个特定状态相关的行为,在抽象状态类中声明了各种不同状态对应的方法,而在其子类中实现类这些方法,由于不同状态下对象的行为可能不同,因此在不同子类中方法的实现可能存在不同,相同的方法可以写在抽象状态类中。
- ConcreteState:它是抽象状态类的子类,每一个子类实现一个与环境类的一个状态相关的行为,每一个具体状态类对应环境的一个具体状态,不同的具体状态类其行为有所不同。
-
优点:
-
去掉了if else结构,使得代码的可维护性更强,不易出错。
-
使用多态代替了条件判断,这样我们代码的扩展性更强。
-
状态可以被共享,减少了系统的负担。
-
状态转换更加的安全,只需要替换相应的状态对象即可。
-
使不同状态的分割变得更加简单。
-
-
缺点:
- if else结构变成对应的状态类,使得系统中类的数量增加了,让系统变得庞大。
- 类的数量增多,也会占用系统的内存。
- 需要经常切换状态,对开闭原则支持不太好。
-
样例:
public interface State { public void handle(Context context); }
public class Context { private State state; public State getState() { return state; } public void setState(State state) { this.state = state; } public Context(State state) { this.state = state; } public void contexthandle(){ state.handle(this); } }
public class ConcreteState implements State { @Override public void handle(Context context) { System.out.println("忙碌状态"); //状态转换 context.setState(new ConcreteStateC()); } }
public class ConcreteStateB implements State { @Override public void handle(Context context) { System.out.println("离线状态"); //状态转换 context.setState(new ConcreteState()); } }
public class ConcreteStateC implements State{ @Override public void handle(Context context) { System.out.println("在线状态"); //状态转换 context.setState(new ConcreteStateB()); } }
public class Client { public static void main(String[] args){ Context context = new Context(new ConcreteStateC()); context.contexthandle(); context.contexthandle(); context.contexthandle(); context.contexthandle(); context.contexthandle(); context.contexthandle(); context.contexthandle(); context.contexthandle(); } }