案例分析:设计模式与代码的结构特性
定义
允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。 其别名为状态对象(Objects for States),状态模式是一种对象行为型模式
动机
在很多情况下,一个对象的行为取决于一个或多个动态变化的属性,这样的属性叫做状态,这样的对象叫做有状态的(stateful)对象,这样的对象状态是从事先定义好的一系列值中取出的。当一个这样的对象与外部事件产生互动时,其内部状态就会改变,从而使得系统的行为也随之发生变化。
结构

组件
- Context(环境类)
环境类又称为上下文类,它是拥有多种状态的对象。由于环境类的状态存在多样性且在不同状态下对象的行为有所不同,因此将状态独立出去形成单独的状态类。在环境类中维护一个抽象状态类State的实例,这个实例定义当前状态,在具体实现时,它是一个State子类的对象。 - State(抽象状态类)
它用于定义一个接口以封装与环境类的一个特定状态相关的行为,在抽象状态类中声明了各种不同状态对应的方法,而在其子类中实现类这些方法,由于不同状态下对象的行为可能不同,因此在不同子类中方法的实现可能存在不同,相同的方法可以写在抽象状态类中 - ConcreteState(具体状态类)
它是抽象状态类的子类,每一个子类实现一个与环境类的一个状态相关的行为,每一个具体状态类对应环境的一个具体状态,不同的具体状态类其行为有所不同。
实现
这里我们模拟一个QQ的状态转换过程
抽象状态类
1 package state; 2 3 public interface State { 4 public void handle(Context context); 5 }
拥有多种状态的对象
1 package state; 2 3 public class Context { 4 private State state; 5 6 public State getState() { 7 return state; 8 } 9 10 public void setState(State state) { 11 this.state = state; 12 } 13 14 public Context(State state) { 15 this.state = state; 16 } 17 18 public void contexthandle(){ 19 state.handle(this); 20 } 21 }
具体状态类
1 package state; 2 3 public class ConcreteState implements State { 4 @Override 5 public void handle(Context context) { 6 System.out.println("忙碌状态"); 7 //状态转换 8 context.setState(new ConcreteStateC()); 9 } 10 }
具体状态类
1 package state; 2 3 public class ConcreteStateB implements State { 4 @Override 5 public void handle(Context context) { 6 System.out.println("离线状态"); 7 //状态转换 8 context.setState(new ConcreteState()); 9 } 10 }
具体状态类
1 package state; 2 3 public class ConcreteStateC implements State{ 4 @Override 5 public void handle(Context context) { 6 System.out.println("在线状态"); 7 //状态转换 8 context.setState(new ConcreteStateB()); 9 } 10 }
客户端
1 package state; 2 3 public class Clinet { 4 public static void main(String[] args) { 5 Context context = new Context(new ConcreteStateC()); 6 context.contexthandle(); 7 context.contexthandle(); 8 context.contexthandle(); 9 System.out.println(); 10 context.contexthandle(); 11 context.contexthandle(); 12 context.contexthandle(); 13 } 14 }
控制台输出

应用案例
共同的特点:对象的行为依赖于它的状态(属性)并且可以根据它的状态改变而改变它的相关行为
- 按钮来控制一个电梯的状态,一个电梯开们,关门,停,运行。每一种状态改变,都有可能要根据其他状态来更新处理。例如,开门状体,你不能在运行的时候开门,而是在电梯定下后才能开门。
- 我们给一部手机打电话,就可能出现这几种情况:用户开机,用户关机,用户欠费停机,用户消户等。 所以当我们拨打这个号码的时候:系统就要判断,该用户是否在开机且不忙状态,又或者是关机,欠费等状态。但不管是那种状态我们都应给出对应的处理操作
- 如在政府OA办公系统中,一个批文的状态有多种:尚未办理;正在办理;正在批示;正在审核;已经完成等各种状态,而且批文状态不同时对批文的操作也有所差异。使用状态模式可以描述工作流对象(如批文)的状态转换以及不同状态下它所具有的行为。
- TCP协议的实现:监听状态,建立连接的状态,关闭状态
- qq登录有不同的状态:忙碌,在线,离线等,不同的状态决定不同的操作
- TCP协议的实现:监听状态,建立连接的状态,关闭状态
优点
- 基于继承的角度
- 它将与特定状态相关的行为局部化,并且将不同状态的行为分割开来
- 避免使用条件if else语句或switch case语句
- 为不同的状态引入独立的对象使得转换变得更加明确
- 将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。
- 基于状态转换的角度
- 可保证Context不会发生内部状态不一致的情况,因为从 Context的角度看,状态转换是原子的—只需重新绑定一个变量(即Context的State对象变量),而无需为多个变量赋值
- 基于内存考虑
- 可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。
缺点
- 状态模式对“开闭原则”的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态;而且修改某个状态类的行为也需修改对应类的源代码。
- 因为该模式将不同状态的行为分布在多个State子类中。这就增加了子类的数目

浙公网安备 33010602011771号