一文小结设计模式之状态模式(Java实现)

简介

当我们需用要程序去描述某个物体的某些事情的时候,并且这些事情会随着这个物体的状态有不同的处理机制。

例如,电梯在运行的时候不可以开门,在停止的时候可以开门;视频在停止的时候只能开启,在播放的时候可以暂停、停止、快进。从这两个例子可以看出,面对物体的当前状态不同,那么他执行的方法也会产生不同的变化

传统方法

我们先来从普通的角度来编写代码;我们可以根据对象当前状态进行判断从而完成我们希望他去执行的方法:

public class Radio{

    String name;
    int state; 

	public void setState(int b){
		this.state = b;
	}

    public void smile() {
        if(this.state == 1){
		
		}else if(this.state == 2){

		}else if(this.state == 3){

		}else{

		}
    }

    public void cry() {
        switch(this.state){
			case 1: 
				 // todo
				 break;
			case 2:
				// todo
				break;
			default:
				// todo
				break;
		}
    }

    public void say() {
        //todo
    }

}

我们可以看到,只是要根据不同状态来决定执行方法,却产生了那么多的if…else语句和switch语句,造成了很多的代码冗余,这个时候我们就可以运用状态模式。

引入状态模式

引入状态模式,我们将每种状态都分离出来,并且使用一个context容器记录当前状态。例如,暂停就单独暂停一个类,播放就单独播放一个类。

我们先看抽象父类方法,将对应的方法全部抽象出来,给子类去完成:

public abstract class AbsStatus {
	// 容器用于记录状态
    protected Context context;

	// 用于改变当前状态的方法,比较重要
    public void setContext(Context context){
        this.context = context;
    }

	// 暂停
    public abstract void close();
	// 停止
    public abstract void stop();
	// 开启播放
    public abstract void open();
	// 加速
    public abstract void speed();

}

停止子类:

public class StopStatus  extends  AbsStatus  {

	// 停止状态下无法暂停了
    @Override
    public void close() {
        System.out.println("停止无法关闭");
    }

	// 本来就停止了不处理
    @Override
    public void stop() {
        System.out.println("本来就停止");
    }

	// 停止状态下可以打开
    @Override
    public void open() {
        System.out.println("切到打开状态");
        // 这两句是核心代码,因为你已经切换到了开打状态,你要通知容器去改变当前状态
        super.context.setAbsStatus(Context.OPEN_STATUS);
        super.context.getAbsStatus();
    }

	// 停止状态无法加速
    @Override
    public void speed() {
        System.out.println("无法加速");
    }
}

状态容器类:

public class Context {

	// 提前定义好各种状态类,后面改状态可直接用
    public static final OpenStatus OPEN_STATUS = new OpenStatus();
    public static final CloseStatus CLOSE_STATUS = new CloseStatus();
    public static final SpeedStatus SPEED_STATUS = new SpeedStatus();
    public static final StopStatus STOP_STATUS = new StopStatus();

	// 聚合一个抽象状态父类
    private AbsStatus absStatus;

	// 设置当前的状态
    public void setAbsStatus(AbsStatus absStatus){
        this.absStatus = absStatus;
        // 一定要把当前状态容器传递抽象父类中
        this.absStatus.setContext(this);
    }

    public AbsStatus getAbsStatus() {
        return absStatus;
    }

    public void close() {
        this.absStatus.close();
    }


    public void stop() {
        this.absStatus.stop();
    }
    public void open() {
        this.absStatus.open();
    }

    public void speed() {
        this.absStatus.speed();
    }

}

同理其他三个状态类也是,下面直接先贴出来了:

播放类

public class OpenStatus  extends  AbsStatus  {

    @Override
    public void close() {
        System.out.println("切到关闭状态");
        super.context.setAbsStatus(Context.CLOSE_STATUS);
        super.context.getAbsStatus();
    }

    @Override
    public void stop() {
        System.out.println("切到关闭状态");
        super.context.setAbsStatus(Context.STOP_STATUS);
        super.context.getAbsStatus();
    }

    @Override
    public void open() {
        System.out.println("本来就打开了");
    }

    @Override
    public void speed() {
        System.out.println("加速加速");
        super.context.setAbsStatus(Context.SPEED_STATUS);
        super.context.getAbsStatus();
    }
}

暂停类:

public class CloseStatus  extends  AbsStatus  {
    @Override
    public void close() {
        System.out.println("关闭就关闭呗");
    }

    @Override
    public void stop() {
        System.out.println("切到暂停");
        super.context.setAbsStatus(Context.STOP_STATUS);
        super.context.getAbsStatus();
    }

    @Override
    public void open() {
        System.out.println("切到打开");
        super.context.setAbsStatus(Context.OPEN_STATUS);
        super.context.getAbsStatus();
    }

    @Override
    public void speed() {
        System.out.println("切到加速");
        super.context.setAbsStatus(Context.SPEED_STATUS);
        super.context.getAbsStatus();
    }
}

加速类:

public class SpeedStatus extends  AbsStatus {
    @Override
    public void close() {
        System.out.println("切到关闭状态");
        super.context.setAbsStatus(Context.CLOSE_STATUS);
        super.context.getAbsStatus();
    }

    @Override
    public void stop() {
        System.out.println("停止");
        super.context.setAbsStatus(Context.STOP_STATUS);
        super.context.getAbsStatus();
    }

    @Override
    public void open() {
        System.out.println("本来就处于打开");
    }

    @Override
    public void speed() {
        System.out.println("本来就加速");
    }
}

正常状态切换结果演示:
在这里插入图片描述

如果拿掉了状态切换:

在这里插入图片描述

注意事项

  • 这里我们需要注意,我们将状态(播放,暂停,停止,加速)装配到了context容器;由context去执行对应的行为
  • 在执行每个行为的时候,都要改变当前context的状态;例如你将收音机从停止状态变到了打开状态,那么需要在停止类调用打开方法的那个方法中改变context的状态,使得当前状态处于打开状态
  • context类中聚合抽象状态父类,是为了面对抽象编程;调用方在调用的时候在具体调用其子类。
  • 抽象状态父类中聚合context容器是为了让状态跟随行为,当发生切换状态的动作时(例如从停止到播放状态),也直接将状态进行了切换。

UML类图

在这里插入图片描述

  • 子类状态继承抽象父类
  • 抽象父类状态和Context容器直接互相聚合

小结

这个模式在生活中很常见,但是却在编程中很少这么写(至少我是这样),不像代理模式天天见。所以了解这个模式需要花点时间揣摩。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值