一、概述
(1)定义:状态模式把所研究的对象的行为包装在不同的状态对象里,每一个状态对象都属于一个抽象状态类的一个子类,这个对象看上去象是改变了它的类一样。状态模式需要对每一个系统可能取得的状态创立一个状态类的子类。当系统的状态变化时,系统便改变所选的子类。
(2)意图:让一个对象在其内部状态改变的时候,其行为也随之改变。
(3)适用场景:1)一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为;2)一个操作中含有庞大的多分支结构,并且这些分支决定于对象的状态。
能够让程序根据不同的外部情况来做出不同的响应,最直接的方法就是在程序中将这些可能发生的外部情况全部考虑到,使用if else语句来进行代码响应选择。但是这种方法对于复杂一点的状态判断,就会显得杂乱无章,容易产生错误;而且增加一个新的状态将会带来大量的修改。这个时候“能够修改自身”的状态模式的引入也许是个不错的主意。状态模式可以有效的替换充满在程序中的if else语句:将不同条件下的行为封装在一个类里面,再给这些类一个统一的父类来约束他们。状态模式主要解决的是当控制一个对象状态的条件表达式过于复杂时的情况,把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简化。
二、结构图
抽象状态(State)角色:定义一个状态接口,用以封装环境(Context)对象的一个特定的状态所对应的行为。
具体状态(ConcreteState)角色:每一个具体状态类都实现了环境(Context)的一个状态所对应的行为。
三、程序实例
1、方式①状态的维护和转换:环境类Context的行为request()是委派给某一个具体状态类的。通过使用多态性原则,可以动态改变环境类Context的属性State的内容,使其从指向一个具体状态类变换到指向另一个具体状态类,从而使环境类的行为request()由不同的具体状态类来执行。
优点:找出应用中需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。业务逻辑类中,将判断分离出“业务逻辑实现类”中,简化其编码和功能。业务逻辑实现类,只是一个平台,提供管理业务逻辑中的动作,而不是具体的操作实现。
缺点:使用状态模式将会导致设计中类的数目大量增加 。
注意:
1、状态之间的转换。①State的转换可以在在状态的处理类内部完成, 但是这样会带来的问题是各个State之间出现了关联, 那么如果一个State本身改变(减少, 增加) 会带来很大影响, 你就有可能看看当前发生改变的state是否也影响到了其它的state的执行。②State的转换也可以由其它类调用Context的setState()来完成, 感觉这种情况更不可靠, 因为这样的话其他类就必须知道Context的特定State, 带来了不必要的耦合, 因此建议对setState()的调用尽量放在Context和State这两处。
2、State的创建和销毁。两个方法: 1.在context内部创建所有state, 一直维护从不销毁.2.在状态转换的时候才创建, 然后上一个state由JVM自动回收. 主要原则需要看实际情况是Context的State的变化是否频繁, 如果不频繁, 建议用第二种,比较优雅。
3、如何选择者两种方式:(1)如果状态转换的规则是一定的,一般不需要进行什么扩展规则,那么就适合在上下文中统一进行状态的维护;(2)如果状态的转换取决于前一个状态动态处理的结果,或者是依赖外部数据,为了增强灵活性,这种情况下,一般式在状态处理类中进行状态的维护。
(1)定义:状态模式把所研究的对象的行为包装在不同的状态对象里,每一个状态对象都属于一个抽象状态类的一个子类,这个对象看上去象是改变了它的类一样。状态模式需要对每一个系统可能取得的状态创立一个状态类的子类。当系统的状态变化时,系统便改变所选的子类。
(2)意图:让一个对象在其内部状态改变的时候,其行为也随之改变。
(3)适用场景:1)一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为;2)一个操作中含有庞大的多分支结构,并且这些分支决定于对象的状态。
能够让程序根据不同的外部情况来做出不同的响应,最直接的方法就是在程序中将这些可能发生的外部情况全部考虑到,使用if else语句来进行代码响应选择。但是这种方法对于复杂一点的状态判断,就会显得杂乱无章,容易产生错误;而且增加一个新的状态将会带来大量的修改。这个时候“能够修改自身”的状态模式的引入也许是个不错的主意。状态模式可以有效的替换充满在程序中的if else语句:将不同条件下的行为封装在一个类里面,再给这些类一个统一的父类来约束他们。状态模式主要解决的是当控制一个对象状态的条件表达式过于复杂时的情况,把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简化。
二、结构图
先创建一个状态接口定义一个操作,然后创建一些实现了该接口具体状态类。Context类持有State的引用。
抽象状态(State)角色:定义一个状态接口,用以封装环境(Context)对象的一个特定的状态所对应的行为。
具体状态(ConcreteState)角色:每一个具体状态类都实现了环境(Context)的一个状态所对应的行为。
三、程序实例
1、方式①状态的维护和转换:环境类Context的行为request()是委派给某一个具体状态类的。通过使用多态性原则,可以动态改变环境类Context的属性State的内容,使其从指向一个具体状态类变换到指向另一个具体状态类,从而使环境类的行为request()由不同的具体状态类来执行。
public interface State {
// 状态对应的处理
public void handle(String sampleParameter);
}
public class ConcreteStateA implements State {
@Override
public void handle(String sampleParameter) {
System.out.println("ConcreteStateA handle :" + sampleParameter);
}
}
public class ConcreteStateB implements State {
@Override
public void handle(String sampleParameter) {
System.out.println("ConcreteStateB handle :" + sampleParameter);
}
}
public class Context {
// 持有一个State类型的对象实例
private State state;
public void setState(State state) {
this.state = state;
}
// 用户感兴趣的接口方法
public void request(String sampleParameter) {
// 转调state来处理
state.handle(sampleParameter);
}
}
public class Client {
public static void main(String[] args) {
// 创建状态
State stateA = new ConcreteStateA();
State stateB = new ConcreteStateB();
// 创建环境
Context context = new Context();
// 将状态设置到环境中
context.setState(stateA);
context.setState(stateB);
// 请求
context.request("testA");
context.request("testB");
}
}
ConcreteStateB handle :testA
ConcreteStateB handle :testB
2、方式②状态的维护和转换:在每一个具体状态角色中来指定后续状态以及何时进行转换(StartHandler)。public interface State {
public void handle(Context context);
}
public class StartState implements State {
public void handle(Context context) {
System.out.println("Start to process...");
context.setCurrentSate(new PublishState());
}
}
public class PublishState implements State {
public void handle(Context context) {
System.out.println("Publish...");
context.setCurrentSate(new CompletedState());
}
}
public class CompletedState implements State {
public void handle(Context context) {
System.out.println("Completed");
context.setCurrentSate(null);
}
}
public class Context {
private State currentSate;
public State getCurrentSate() {
return currentSate;
}
public void setCurrentSate(State currentSate) {
this.currentSate = currentSate;
}
}
public class Client {
public static void main(String[] args) {
Context context = new Context();
context.setCurrentSate(new StartState());
while (context.getCurrentSate() != null) {
context.getCurrentSate().handle(context);
}
System.out.println("Exit...");
}
}
Start to process...
Publish...
Completed
Exit...
四、特点优点:找出应用中需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。业务逻辑类中,将判断分离出“业务逻辑实现类”中,简化其编码和功能。业务逻辑实现类,只是一个平台,提供管理业务逻辑中的动作,而不是具体的操作实现。
缺点:使用状态模式将会导致设计中类的数目大量增加 。
注意:
1、状态之间的转换。①State的转换可以在在状态的处理类内部完成, 但是这样会带来的问题是各个State之间出现了关联, 那么如果一个State本身改变(减少, 增加) 会带来很大影响, 你就有可能看看当前发生改变的state是否也影响到了其它的state的执行。②State的转换也可以由其它类调用Context的setState()来完成, 感觉这种情况更不可靠, 因为这样的话其他类就必须知道Context的特定State, 带来了不必要的耦合, 因此建议对setState()的调用尽量放在Context和State这两处。
2、State的创建和销毁。两个方法: 1.在context内部创建所有state, 一直维护从不销毁.2.在状态转换的时候才创建, 然后上一个state由JVM自动回收. 主要原则需要看实际情况是Context的State的变化是否频繁, 如果不频繁, 建议用第二种,比较优雅。
3、如何选择者两种方式:(1)如果状态转换的规则是一定的,一般不需要进行什么扩展规则,那么就适合在上下文中统一进行状态的维护;(2)如果状态的转换取决于前一个状态动态处理的结果,或者是依赖外部数据,为了增强灵活性,这种情况下,一般式在状态处理类中进行状态的维护。