庄陶模式非常简单,就是根据某一个类值的变化,显示不同的状态,也可以有不同的操作,我们经常会用到。
还是举个栗子:
当我们打电话的时候,有呼叫中,通话总,通话结束,还有一个是通话中有另一个人再次呼入的多方呼叫状态,根据不用的状态,我们可以选择是接听还是挂断。
/**
* @author: hx
* @Time: 2019/5/23
* @Description: State
*/
public class State {
/**
* 状态值,0位初始值,1位呼叫中,2为通话中,3为通话结束,4为多方呼叫,5为来电
*/
private int State = 0;
public int getState() {
return State;
}
public void setState(int state) {
State = state;
}
}
/**
* @author: hx
* @Time: 2019/5/23
* @Description: Call
*/
public class Call {
private State mState;
public Call(State state) {
mState = state;
}
public State getState() {
return mState;
}
public void setState(State state) {
mState = state;
}
public void conver(){
switch(mState.getState()){
case 1:
System.out.println("当前为呼叫,可挂断");
break;
case 2:
System.out.println("当前为通话中,可挂断");
break;
case 3:
System.out.println("当前为通话结束,不可操作");
break;
case 4:
System.out.println("当前为多方通话,可切换,可挂断");
break;
case 5:
System.out.println("当前为来电,可接听,可挂断");
break;
default:
System.out.println("当前状态异常");
break;
}
}
}
简单的试一下
public static void main(String[] args){
State state = new State();
Call call = new Call(state);
call.conver();
state.setState(1);
call.conver();
state.setState(3);
call.conver();
state.setState(4);
call.conver();
state.setState(5);
call.conver();
state.setState(2);
call.conver();
}
输出结果:
当前状态异常
当前为呼叫,可挂断
当前为通话结束,不可操作
当前为多方通话,可切换,可挂断
当前为来电,可接听,可挂断
当前为通话中,可挂断
在上面原始的例子当中,我们的Call类当中有明显的分支判断结构,这明显不是符合开闭原则的。
状态模式主要解决的是当一个对象状态的条件表达式过于复杂时的时候,把状态的判断逻辑转移到表示不同状态的一系列类中,把复杂的判断逻辑简化。
原理的代码就不用了,修改一下代码
一个管理呼叫的类,还是叫Call
/**
* @author: hx
* @Time: 2019/5/23
* @Description: Call
*/
public class Call {
public static CallState CALL_OUT;
public static CallState TALKING;
public static CallState CALL_END;
public static CallState INCOMMING;
private CallState mState;
public Call() {
CALL_OUT = new CallOut(this);
TALKING = new Talking(this);
CALL_END = new CallEnd(this);
INCOMMING = new Incomming(this);
}
public CallState getState() {
return mState;
}
public void setState(CallState state) {
mState = state;
}
public void callOut(){
mState.callOut();
}
public void talking(){
mState.talking();
}
public void callend(){
mState.callEnd();
}
public void incomming(){
mState.incomming();
}
}
一个呼叫状态的抽象父类
/**
* @author: hx
* @Time: 2019/5/24
* @Description: CallState 呼叫状态抽象列
*/
public abstract class CallState {
/**
* 持有一个呼叫的引用
*/
protected Call mCall;
public CallState(Call call) {
mCall = call;
}
public void setCall(Call call) {
mCall = call;
}
/**
* 呼出状态
*/
public abstract void callOut();
/**
* 通话状态
*/
public abstract void talking();
/**
* 通话结束状态
*/
public abstract void callEnd();
/**
* 来电状态
*/
public abstract void incomming();
}
接下来就是呼叫的状态类
/**
* @author: hx
* @Time: 2019/5/24
* @Description: CallOut
*/
public class CallOut extends CallState {
public CallOut(Call call) {
super(call);
}
@Override
public void callOut() {
System.out.println("已经是呼出状态,不能再呼出");
}
@Override
public void talking() {
System.out.println("呼出状态,对方接听了");
mCall.setState(Call.TALKING);
}
@Override
public void callEnd() {
System.out.println("呼出状态,通话中断,呼叫结束");
mCall.setState(Call.CALL_END);
}
@Override
public void incomming() {
System.out.println("呼出状态,不能接受别人的呼叫");
}
}
/**
* @author: hx
* @Time: 2019/5/24
* @Description: Talking
*/
public class Talking extends CallState {
public Talking(Call call) {
super(call);
}
@Override
public void callOut() {
System.out.println("通话状态,不能再呼出");
}
@Override
public void talking() {
System.out.println("通话状态,不能再建立新的通话");
}
@Override
public void callEnd() {
System.out.println("通话状态,通话结束");
mCall.setState(Call.CALL_END);
}
@Override
public void incomming() {
System.out.println("通话状态,不接受呼入");
}
}
/**
* @author: hx
* @Time: 2019/5/24
* @Description: CallEnd
*/
public class CallEnd extends CallState {
public CallEnd(Call call) {
super(call);
}
@Override
public void callOut() {
System.out.println("通话结束,再次呼出");
mCall.setState(Call.CALL_OUT);
}
@Override
public void talking() {
System.out.println("通话结束,无来电,不可通话");
}
@Override
public void callEnd() {
System.out.println("通话结束,不能再次结束");
}
@Override
public void incomming() {
System.out.println("通话结束,有新的来电");
mCall.setState(Call.INCOMMING);
}
}
/**
* @author: hx
* @Time: 2019/5/24
* @Description: Incomming
*/
public class Incomming extends CallState {
public Incomming(Call call) {
super(call);
}
@Override
public void callOut() {
System.out.println("来电状态,不能再呼出");
}
@Override
public void talking() {
System.out.println("来电状态,接听了电话");
mCall.setState(Call.TALKING);
}
@Override
public void callEnd() {
System.out.println("来电状态,拒接了电话");
mCall.setState(Call.CALL_END);
}
@Override
public void incomming() {
System.out.println("来电状态,不能再接受来电");
}
}
增加了很多类,但是每个状态的操作也更加清晰了,每个状态负责自己状态的事情。
看看调用
public static void main(String[] args){
Call call = new Call();
call.setState(Call.CALL_END);
System.out.println("------------呼叫--挂断----------");
//呼叫--挂断
call.callOut();
call.callend();
System.out.println("------------来电--挂断----------");
//来电--挂断
call.incomming();
call.callend();
System.out.println("----------呼叫--接听--挂断------------");
// 呼叫--接听--挂断
call.callOut();
call.talking();
call.callend();
System.out.println("----------来电--接听--挂断------------");
//来电--接听--挂断
call.incomming();
call.talking();
call.callend();
System.out.println("----------错误状态演示 来电--来电--接听--呼出--来电--挂断------------");
//错误状态演示 来电--来电--接听--呼出--来电--挂断
call.incomming();
call.incomming();
call.talking();
call.callOut();
call.incomming();
call.callend();
}
输出结果:
------------呼叫--挂断----------
通话结束,再次呼出
呼出状态,通话中断,呼叫结束
------------来电--挂断----------
通话结束,有新的来电
来电状态,拒接了电话
----------呼叫--接听--挂断------------
通话结束,再次呼出
呼出状态,对方接听了
通话状态,通话结束
----------来电--接听--挂断------------
通话结束,有新的来电
来电状态,接听了电话
通话状态,通话结束
----------错误状态演示 来电--来电--接听--呼出--来电--挂断------------
通话结束,有新的来电
来电状态,不能再接受来电
来电状态,接听了电话
通话状态,不能再呼出
通话状态,不接受呼入
通话状态,通话结束
优点
结构清晰,避免太多的分支结构语句 switch- case 或者 if- else 的使用,可维护性有所提高。
封装性强,遵循设计原则,很好地体现了开闭原则和单一职责原则
缺点
缺点很明显,那就是子类会太多,因为每一个状态都对应一个子类,所以当你的状态非常多的时候就会发生类膨胀。而且当需要增状态的时候,需要修改各个子类的中对新增状态的处理,不符合开闭原则。
状态模式和策略模式的区别
状态模式和策略模式有相似的类图, 但是它们的目的还是不同的。策略模式侧重对行为或算法的替换,并且可以动态替换,使用不同算法来解决问题。而状态模式更侧重状态的改变而改变行为,而行为执行的结果又会导致状态发生变化,是一个状态和行为的变化过程。
使用场景
行为随着状态的改变而改变的时候,这是状态模式的根本出发点,例如权限等级的设计。
条件、分支判断语句的替代者,当程序中大量使用 switch 语句或者if-else判断语句会导致程序结构不清晰,使用状态模式可以很好地避免这一问题。
虽然状态模式可以很好的处理行为随着状态的改变而变化,但是随着类的增加,管理起来也是很麻烦,假如有几十种状态,还是需要慎重。