概念
当一个对象内在状态改变时,允许其改变行为,这个对象看起来像是改变了其类。也就是说,状态模式把对象的状态转换封装起来,当状态发生改变时,引起了行为发生改变,从外部看像是对象对应的类发生改变。
实现
案例:我就举一个我们最熟悉的案例——手机,手机的状态有很多种,这次我就简化手机的状态,只拿出4种状态进行举例:通话状态、锁屏状态、联网状态、充电状态。
我们都知道,在通话状态下,我们可以接收其他的来电;当我们把手机放到耳边,手机会进行自动锁屏;如果通话到一半,我们还可以充着电(这个可行,但不太建议)。
在锁屏状态下,我们可以接收来电,还可以联网和锁屏。
在联网状态下,我们可以锁屏或者充电。
在充电状态下,我们可以进行锁屏,联网,还可以接收来电。
整理可得:
首先定义一个手机状态的抽象类:
/**
* 定义一个用于表示手机状态的抽象类
*/
public abstract class PhoneState {
//定义一个封装的状态对象
public StateContext stateContext;
//定义一个设置状态的方法
public void setStateContext(StateContext stateContext){
this.stateContext = stateContext;
}
//定义手机的操作:来电,锁屏,联网,充电
//定义手机来电操作
public abstract void call();
//定义手机锁屏操作
public abstract void lock();
//定义手机联网操作
public abstract void net();
//定义手机充电操作
public abstract void charging();
}
再定义一个环境角色,用于串联各个状态
/**
* 定义一个环境角色,用于串联各个状态
*/
public class StateContext {
//实例手机的所有状态
public final static CallingState callingState = new CallingState();
public final static LockState lockState = new LockState();
public final static NetState netState = new NetState();
public final static ChargingState chargingState = new ChargingState();
//定义手机
private PhoneState phoneState;
//获取手机当前状态
public PhoneState getPhoneState() {
return phoneState;
}
//设置当前手机状态
public void setPhoneState(PhoneState phoneState){
this.phoneState = phoneState;
//实现状态之间不同状态对象的跳转
this.phoneState.setStateContext(this);
}
public void call(){
this.phoneState.call();
}
public void lock(){
this.phoneState.lock();
}
public void net(){
this.phoneState.net();
}
public void charging(){
this.phoneState.charging();
}
}
把手机各个状态进行具体代码逻辑的实现:
/**
* 定义通话时可执行的操作
*/
public class CallingState extends PhoneState {
//通话时要实现的动作
@Override
public void call() {
System.out.println("您的号码正在通话中");
}
//通话时进行锁屏
@Override
public void lock() {
super.stateContext.setPhoneState(StateContext.lockState);
super.stateContext.getPhoneState().lock();
}
//通话时,无法联网
@Override
public void net() {
//do nothing
}
//通话时,充电操作
@Override
public void charging() {
super.stateContext.setPhoneState(StateContext.chargingState);
super.stateContext.getPhoneState().charging();
}
}
/**
* 定义锁屏时可执行的操作
*/
public class LockState extends PhoneState {
//锁屏状态下,来电
@Override
public void call() {
super.stateContext.setPhoneState(StateContext.callingState);
super.stateContext.getPhoneState().call();
}
//锁屏要执行的操作
@Override
public void lock() {
System.out.println("您的手机正在锁屏!");
}
//锁屏状态下联网操作
@Override
public void net() {
super.stateContext.setPhoneState(StateContext.netState);
super.stateContext.getPhoneState().net();
}
//锁屏状态下,充电操作
@Override
public void charging() {
super.stateContext.setPhoneState(StateContext.chargingState);
super.stateContext.getPhoneState().charging();
}
}
/**
* 定义联网时可执行的操作
*/
public class NetState extends PhoneState {
//联网时打不了电话
@Override
public void call() {
//do nothing
}
//联网时,可以锁屏
@Override
public void lock() {
super.stateContext.setPhoneState(StateContext.lockState);
super.stateContext.getPhoneState().lock();
}
//联网的具体操作
@Override
public void net() {
System.out.println("您的手机联网成功.....");
}
//联网时,可以充电
@Override
public void charging() {
super.stateContext.setPhoneState(StateContext.chargingState);
super.stateContext.getPhoneState().charging();
}
}
/**
* 定义充电时可执行的操作
*/
public class ChargingState extends PhoneState {
//充电时,可以来电
@Override
public void call() {
super.stateContext.setPhoneState(StateContext.callingState);
super.stateContext.getPhoneState().call();
}
//充电时,可以锁屏
@Override
public void lock() {
super.stateContext.setPhoneState(StateContext.lockState);
super.stateContext.getPhoneState().lock();
}
//充电时可以联网
@Override
public void net() {
super.stateContext.setPhoneState(StateContext.netState);
super.stateContext.getPhoneState().net();
}
//充电的具体操作
@Override
public void charging() {
System.out.println("您的手机正在充电");
}
}
用客户端进行测试,本次客户端只进行了一种状态的测试:
public class Client {
public static void main(String[] args) {
StateContext stateContext = new StateContext();
//来电时
stateContext.setPhoneState(StateContext.callingState);
stateContext.call();
stateContext.net();
stateContext.charging();
stateContext.net();
}
}
实验结果:
优点:避免了使用过多的条件判断语句,使程序看起来更加简化,较好地体现了开闭原则,单一职责原则,封装了转换规则,客户端不需要知道状态的转换是如何实现的。
缺点:如果对象状态很多,需要实现的子类也会相应复杂
本文的代码:https://pan.baidu.com/s/1heOeGEEpqVzXywz9BysHGg
提取码:k9rf