最近发现项目中的判断太多,大量的if-else结构,想着重构下,于是接触到了状态模式。
这种设计模式就是java多态的体现,没有想象的那么神奇。
状态模式:当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。
即
1、有一个对象,它是有状态的。
2、这个对象在状态不同的时候,行为不一样。
3、这些状态是可以切换的,而非毫无关系。
图中包含三个角色。
Context:它就是那个含有状态的对象,它可以处理一些请求,这些请求最终产生的响应会与状态相关。
State:状态接口,它定义了每一个状态的行为集合,这些行为会在Context中得以使用。
ConcreteState:具体状态,实现相关行为的具体状态类。
其他解释
环境(Context)角色,也成上下文:定义客户端所感兴趣的接口,并且保留一个具体状态类的实例。这个具体状态类的实例给出此环境对象的现有状态。
抽象状态(State)角色:定义一个接口,用以封装环境(Context)对象的一个特定的状态所对应的行为。
具体状态(ConcreteState)角色:每一个具体状态类都实现了环境(Context)的一个状态所对应的行为。
个人还是喜欢把环境角色context带入接口的方法参数中,这样逻辑更清楚;
另外的方式是把context放入各个具体状态角色的构造方法中,当实例化context的时候,通过具体状态的构造方法加载此context实例到具体状态角色中
举例一
本例子模拟购物的整个过程,包括下单,付款,收货,评价,退款,结束等。
状态接口
public interface Event {
//下单
void order(Shopping shopping,Boolean isConfirm) ;
//付款
void pay(Shopping shopping,Boolean isConfirm);
//签收
void receive(Shopping shopping,Boolean isConfirm);
//评价
void evaluate(Shopping shopping,Boolean isConfirm);
//订单结束
void finish(Shopping shopping,Boolean isConfirm);
//退款
void refund(Shopping shopping,Boolean isConfirm);
}
抽象类主要处理异常的情况,即用户重复提交某个状态时出现
public class AbstractEvent implements Event {
@Override
public void order(Shopping shopping, Boolean isConfirm) {
System.out.println("亲亲,下单异常");
}
@Override
public void pay(Shopping shopping, Boolean isConfirm) {
System.out.println("亲亲,支付异常");
}
@Override
public void receive(Shopping shopping, Boolean isConfirm) {
System.out.println("亲亲,接收异常");
}
@Override
public void evaluate(Shopping shopping, Boolean isConfirm) {
System.out.println("亲亲,评价异常");
}
@Override
public void finish(Shopping shopping, Boolean isConfirm) {
System.out.println("亲亲,结束操作流程错误");
}
@Override
public void refund(Shopping shopping, Boolean isConfirm) {
System.out.println("您的订单已经退款,请不要重复提交");
}
}
具体状态角色 - 下单
public class Order extends AbstractEvent {
@Override
public void order(Shopping shopping, Boolean isConfirm) {
if(isConfirm){
System.out.println("恭喜您,下单成功");
shopping.setEvent(Shopping.PAY_STATE);//确定下单,进入支付页面
}else {
System.out.println("订单页面取消成功,回到主页面");
shopping.setEvent(Shopping.REFUND);
}
}
}
具体状态角色 - 支付
public class Pay extends AbstractEvent {
@Override
public void pay(Shopping shopping, Boolean isConfirm) {
if(isConfirm){
System.out.println("恭喜您,支付成功");
shopping.setEvent(Shopping.RECEIVE_STATE);//进入收货阶段
}else {
System.out.println("支付页面,取消订单成功");
shopping.setEvent(Shopping.REFUND);
}
}
}
具体状态角色 - 接收
public class Receive extends AbstractEvent {
@Override
public void receive(Shopping shopping, Boolean isConfirm) {
if(isConfirm){
System.out.println("亲,签收物品成功,期待下次与您再次相见");
shopping.setEvent(Shopping.EVALUATE_STATE);
}else {
System.out.println("亲,签收阶段退款成功");
shopping.setEvent(Shopping.REFUND);
}
}
}
具体状态角色 - 评价
public class Evaluate extends AbstractEvent {
@Override
public void evaluate(Shopping shopping, Boolean isConfirm) {
if(isConfirm){
System.out.println("评价商品成功");
shopping.setEvent(Shopping.FINISH_STATE);
}else {
System.out.println("评价阶段,退款成功");
shopping.setEvent(Shopping.REFUND);
}
}
}
具体状态角色 - 完成
public class Finish extends AbstractEvent {
@Override
public void finish(Shopping shopping, Boolean isConfirm) {
if(isConfirm){
System.out.println("订单结束,感谢您的光临");
}else {
System.out.println("亲爱的客人,请您分享使用心得");
}
}
}
具体状态角色 - 退款
public class Refund extends AbstractEvent {
@Override
public void refund(Shopping shopping, Boolean isConfirm) {
if(isConfirm){
System.out.println("抱歉客官,给您带来不好的购物体验了,已为您退款,请见谅");
shopping.setEvent(Shopping.FINISH_STATE);
}
}
}
环境角色,有状态的对象 - 购物对象
public class Shopping {
public static final Event ORDER_STATE = new Order();
public static final Event PAY_STATE = new Pay();
public static final Event RECEIVE_STATE = new Receive();
public static final Event EVALUATE_STATE = new Evaluate();
public static final Event FINISH_STATE = new Finish();
public static final Event REFUND = new Refund();
//状态记录,默认进入下单状态
private Event event = ORDER_STATE;
public Event getEvent() {
return event;
}
public void setEvent(Event event) {
this.event = event;
}
public void startOrder(Boolean isConfirm){
event.order(this,isConfirm);
}
public void startPay(Boolean isConfirm){
event.pay(this,isConfirm);
}
public void startReceive(Boolean isConfirm){
event.receive(this,isConfirm);
}
public void startEvaluate(Boolean isConfirm){
event.evaluate(this,isConfirm);
}
public void startFinish(Boolean isConfirm){
event.finish(this,isConfirm);
}
public void startRefund(Boolean isConfirm){
event.refund(this,isConfirm);
}
}
客户启动段
public class Client {
public static void main(String[] args) {
Shopping shopping = new Shopping();
//下单成功
shopping.startOrder(true);
shopping.startOrder(true);
shopping.startOrder(true);
shopping.startOrder(true);
shopping.startOrder(true);
shopping.startPay(true);
shopping.startReceive(false);
shopping.startRefund(true);
shopping.startEvaluate(true);
shopping.startFinish(true);
}
}
运行结果:
举例二
理论基础自带
环境角色,包含状态实例
//英雄类
public class Hero {
public static final RunState COMMON = new CommonState();//正常状态
public static final RunState SPEED_UP = new SpeedUpState();//加速状态
public static final RunState SPEED_DOWN = new SpeedDownState();//减速状态
public static final RunState SWIM = new SwimState();//眩晕状态
private RunState state = COMMON;//默认是正常状态
private Thread runThread;//跑动线程
//设置状态
public void setState(RunState state) {
this.state = state;
}
//停止跑动
public void stopRun() {
if (isRunning()) runThread.interrupt();
System.out.println("--------------停止跑动---------------");
}
//开始跑动
public void startRun() {
if (isRunning()) {
return;
}
final Hero hero = this;
runThread = new Thread(new Runnable() {
public void run() {
while (!runThread.isInterrupted()) {
state.run(hero);
}
}
});
System.out.println("--------------开始跑动---------------");
runThread.start();
}
private boolean isRunning(){
return runThread != null && !runThread.isInterrupted();
}
}
接口定义
public interface RunState {
void run(Hero hero);
}
具体状态模式
正常模式
public class CommonState implements RunState{
public void run(Hero hero) {
//正常跑动则不打印内容
}
}
加速
public class SpeedUpState implements RunState{
public void run(Hero hero) {
System.out.println("--------------加速跑动---------------");
try {
Thread.sleep(4000);//假设加速持续4秒
} catch (InterruptedException e) {}
hero.setState(Hero.COMMON);
System.out.println("------加速状态结束,变为正常状态------");
}
}
减速
public class SpeedDownState implements RunState{
public void run(Hero hero) {
System.out.println("--------------减速跑动---------------");
try {
Thread.sleep(4000);//假设减速持续4秒
} catch (InterruptedException e) {}
hero.setState(Hero.COMMON);
System.out.println("------减速状态结束,变为正常状态------");
}
}
控制
public class SwimState implements RunState{
public void run(Hero hero) {
System.out.println("--------------不能跑动---------------");
try {
Thread.sleep(2000);//假设眩晕持续2秒
} catch (InterruptedException e) {}
hero.setState(Hero.COMMON);
System.out.println("------眩晕状态结束,变为正常状态------");
}
}
客户启动端
public class Client{
public static void main(String[] args) throws InterruptedException {
Hero hero = new Hero();
hero.startRun();
hero.setState(Hero.SPEED_UP);
Thread.sleep(5000);
hero.setState(Hero.SPEED_DOWN);
Thread.sleep(5000);
hero.setState(Hero.SWIM);
Thread.sleep(5000);
hero.stopRun();
}
}
状态模式解决的问题:状态模式主要解决的是当控制一个对象状态的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简化。
状态模式优点:
一、我们去掉了if else结构,使得代码的可维护性更强,不易出错,这个优点挺明显,如果试图让你更改跑动的方法,是刚才的一堆if else好改,还是分成了若干个具体的状态类好改呢?答案是显而易见的。
二、使用多态代替了条件判断,这样我们代码的扩展性更强,比如要增加一些状态,假设有加速20%,加速10%,减速10%等等等,会非常的容易。
三、状态是可以被共享的,这个在上面的例子当中有体现,看下Hero类当中的四个static final变量就知道了,因为状态类一般是没有自己的内部状态的,所有它只是一个具有行为的对象,因此是可以被共享的。
四、状态的转换更加简单安全,简单体现在状态的分割,因为我们把一堆if else分割成了若干个代码段分别放在几个具体的状态类当中,所以转换起来当然更简单,而且每次转换的时候我们只需要关注一个固定的状态到其他状态的转换。安全体现在类型安全,我们设置上下文的状态时,必须是状态接口的实现类,而不是原本的一个整数,这可以杜绝魔数以及不正确的状态码。
状态模式适用于某一个对象的行为取决于该对象的状态,并且该对象的状态会在运行时转换,又或者有很多的if else判断,而这些判断只是因为状态不同而不断的切换行为。
状态模式缺点:
1、会增加的类的数量。
2、使系统的复杂性增加。
尽管状态模式有着这样的缺点,但是往往我们牺牲复杂性去换取的高可维护性和扩展性是相当值得的,除非增加了复杂性以后,对于后者的提升会乎其微。
状态模式在项目当中也算是较经常会碰到的一个设计模式,但是通常情况下,我们还是在看到if else的情况下,对项目进行重构时使用,又或者你十分确定要做的项目会朝着状态模式发展,一般情况下,还是不建议在项目的初期使用。
理论学习借鉴:
https://www.cnblogs.com/zuoxiaolong/p/pattern22.html