设计模式——状态模式

状态模式

状态模式:当一个对象内在状态改变时允许其改变行为,这个对象看起来像改变了其类。

状态模式的核心是封装,状态的变更引起了行为的变更,从外部看起来就好像这个对象对应的类发生了改变一样。

状态模式的角色:

  • State抽象状态角色:接口或抽象类,负责对象状态定义,并且封装环境角色以实现状态切换。
  • ConcreteState具体状态角色:每一个具体状态必须完成本状态下要做的事情,以及本状态如何过渡到其他状态。
  • Context环境角色:定义客户端需要的接口,并且负责具体状态的切换

抽象状态角色State:

public abstract class State { 
    //定义一个环境角色,提供子类访问 
    protected Context context; 
    //设置环境角色 
    public void setContext(Context _context){ 
        this.context = _context; 
    }
    //行为 
    public abstract void handle1(); 
    public abstract void handle2(); 
}

具体状态角色ConcreteState1~2:

public class ConcreteState1 extends State {@Override 
    public void handle1() { 
        //本状态下必须处理的逻辑 
    }
    @Override 
    public void handle2() { 
        //设置当前状态为stat2 
        super.context.setCurrentState(Context.STATE2); 
        //过渡到state2状态,由Context实现 
        super.context.handle2(); 
    } 
}

public class ConcreteState2 extends State { 
    @Override 
    public void handle1() { 
        //设置当前状态为state1 
        super.context.setCurrentState(Context.STATE1); 
        //过渡到state1状态,由Context实现 
        super.context.handle1(); 
    }
    @Override 
    public void handle2() { 
        //本状态下必须处理的逻辑 
    } 
}

环境角色Context:

public class Context { 
    //定义状态 
    public final static State STATE1 = new ConcreteState1(); 
    public final static State STATE2 = new ConcreteState2(); 
    //当前状态 
    private State CurrentState; 
    //获得当前状态 
    public State getCurrentState() { 
        return CurrentState; 
    }
    //设置当前状态 
    public void setCurrentState(State currentState) { 
        this.CurrentState = currentState; 
        //切换状态 
        this.CurrentState.setContext(this); 
    }
    //行为委托 
    public void handle1(){ 
        this.CurrentState.handle1(); 
    }
    public void handle2(){ 
        this.CurrentState.handle2(); 
    }
}

环境角色有两个不成文的约束:

  • 把状态对象声明为静态常量,有几个状态对象就声明几个静态常量。
  • 环境角色具有状态抽象角色定义的所有行为,具体执行使用委托方式

场景类Client:

public class Client { 
    public static void main(String[] args) { 
        //定义环境角色 
        Context context = new Context(); 
        //初始化状态 
        context.setCurrentState(new ConcreteState1()); 
        //行为执行 
        context.handle1(); 
        context.handle2(); 
    } 
}

状态模式的优点

  • 结构清晰。
  • 遵循开闭原则和单一职责原则:每个状态都是一个子类,你要增加状态就要增加子类,你要修改状态,你只修改一个子类就可以了。
  • 封装性好:这是状态模式的基本要求,状态变换放置到类的内部来实现,外部的调用不用知道类内部如何实现状态和行为的变换。

状态模式的缺点

如果状态较多,则子类会太多。

状态模式的使用场景

  • 行为随状态改变而改变的场景。
  • 条件、分支判断语句的替代者。

状态模式的注意事项

状态模式适用于当某个对象在它的状态发生改变时,它的行为也随着发生比较大的变化,也就是说在行为受状态约束的情况下可以使用状态模式,而且使用时对象的状态最好不要超过5个


状态模式的实例

电梯运行,包含四个状态:开门、关门、运行、停止。

(1)电梯抽象类LiftState 

import com.sfq.action.Context;
public abstract class LiftState {
	protected Context context;
	public void setContext(Context context) {
		this.context = context;
	}
	public abstract void open();
	public abstract void close();
	public abstract void run();
	public abstract void stop();
}

(2)LiftState 的四个实现类

import com.sfq.impl.LiftState;
public class OpenningState extends LiftState {
	@Override
	public void open() {
		System.out.println("电梯门开启...");
	}
	@Override
	public void close() {
		//状态修改
		super.context.setLiftState(Context.closingState);
		//动作委托为CloseState来执行
		super.context.getLiftState().close();
	}
	@Override
	public void run() {
		// nothing
	}
	@Override
	public void stop() {
		// nothing
	}
}
public class ClosingState extends LiftState {
	@Override
	public void open() {
		super.context.setLiftState(Context.openningState);
		super.context.getLiftState().open();
	}
	@Override
	public void close() {
		System.out.println("电梯门关闭...");
	}
	@Override
	public void run() {
		super.context.setLiftState(Context.runningState);
		super.context.getLiftState().run();
	}
	@Override
	public void stop() {
		super.context.setLiftState(Context.stoppingState);
		super.context.getLiftState().stop();
	}
}
import com.sfq.impl.LiftState;
public class RunningState extends LiftState {
	@Override
	public void open() {
		// nothing
	}
	@Override
	public void close() {
		// nothing
	}
	@Override
	public void run() {
		System.out.println("电梯上下运行...");
	}
	@Override
	public void stop() {
		super.context.setLiftState(Context.stoppingState);
		super.context.getLiftState().stop();
	}
}
import com.sfq.impl.LiftState;
public class StoppingState extends LiftState {
	@Override
	public void open() {
		super.context.setLiftState(Context.openningState);
		super.context.getLiftState().open();
	}
	@Override
	public void close() {
		// nothing
	}
	@Override
	public void run() {
		super.context.setLiftState(Context.runningState);
		super.context.getLiftState().run();
	}
	@Override
	public void stop() {
		System.out.println("电梯停了...");
	}
}

(3)环境类Context

public class Context {
	public final static OpenningState openningState = new OpenningState();
	public final static ClosingState closingState = new ClosingState();
	public final static RunningState runningState = new RunningState();
	public final static StoppingState stoppingState = new StoppingState();	
	//定义电梯当前状态
	private LiftState liftState;
	public LiftState getLiftState() {
		return liftState;
	}
	public void setLiftState(LiftState liftState) {
		this.liftState = liftState;
		//把当前的环境通知到各个实现类中
		this.liftState.setContext(this);
	}
	public void open() {
		this.liftState.open();
	}
	public void close() {
		this.liftState.close();
	}
	public void run() {
		this.liftState.run();
	}
	public void stop() {
		this.liftState.stop();
	}
}

(4)场景类Client

import com.sfq.action.ClosingState;
import com.sfq.action.Context;
public class Client {
	public static void main(String[] args) {
		Context context = new Context();
		context.setLiftState(new ClosingState());
		context.open();
		context.close();
		context.run();
		context.stop();
	}
}

结果
电梯门开启...
电梯门关闭...
电梯上下运行...
电梯停了...

Client场景类,只要定义一个电梯的初始状态,然后调用相关的方法,就完成了,完全不用考虑状态的变更。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

肥羊汤

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值