Java设计模式之状态模式(State)

1. 引入状态模式

(该例子引入《大话设计模式》)

作为程序员,加班是家常便饭。我们就每日的工作状态写一下。

9:00-11:00 上午上班

11:00-13:00 午休

13:00-18:00 下午上班

18:00 下班

18:00 以后 加班

用代码表示如下:

public class WholeWork {

	private int hour;
	private boolean finished;
	
	public void writeProgram() {
		hour = this.getHour();
		if(hour<11) {
			System.out.println(hour+"点了,上午上班中");
		} else if(hour<13) {
			System.out.println(hour+"点了,午休中");
		} else if(hour<18) {
			System.out.println(hour+"点了,下午上班中");
		} else{
			if(finished) {
				System.out.println(hour+"点了,下班了");
			} else {
				if(hour<21) {
					System.out.println(hour+"点了,加班中");
				}else {
					System.out.println(hour+"点了,还在持续加班中,太困了,要睡着了");
				}
			}
		}
	}
	
	public int getHour() {
		return hour;
	}
	public void setHour(int hour) {
		this.hour = hour;
	}
	public boolean isFinished() {
		return finished;
	}
	public void setFinished(boolean finished) {
		this.finished = finished;
	}
}

测试类:

public class WholeTest {
	
	public static void main(String[] args) {
		WholeWork work = new WholeWork();
		
		work.setHour(9);
		work.writeProgram();
		work.setHour(12);
		work.writeProgram();
		work.setHour(16);
		
//		work.setFinished(true);
		
		work.writeProgram();
		work.setHour(20);
		work.writeProgram();
		work.setHour(23);
		work.writeProgram();

	}

}

结果:

需求达到了,但从代码可以看出这么几个问题:

  • WholeWork类中的writeProgram方法过长,if判断分支过多,责任过大,所有的逻辑判断都写在这个方法里,违背了单一职责原则。
  • 如果修改需求,比如说改成17:30下班,或者要求21点前必须下班,修改需求后,需要做的改动比较大,这就违背了开放-封闭原则。

为了解决这种要求在不同状态下需要发生不同的行为,这就需要一种新的模式——状态模式。

2. 状态模式

2.1 定义

状态模式,当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。(引自《大话设计模式》)

2.2 解释

其实,就是说当一个对象的状态转换的条件表达式过于复杂时,可以将状态变化的判断逻辑转移到其他一系列类中去。就比如说上面的例子,9:00-11:00,11:00-13:00,等等,有这么多的状态条件判断,我们可以把这些判断分散到一系列类中,这样不仅解了耦,代码也变得简单明了,方便维护。

当然了,这里只适用状态判断复杂的情况,如果情况简单,比如只需要两个判断,那么if-else就可以搞定了,无需什么状态模式了。

2.3 结构图

 

  • Context类,上下文,定义状态。
  • State类,抽象状态类,或接口类,定义了一个与Context状态相关联的行为方法。
  • ConcreteState类,具体实现类,实现State的方法,实现与Context状态相关联的行为方法。

2.4 基本代码

State

public interface State {

	void handle(Context context);
}

Context上下文,定义了状态

public class Context {
	public State state;

	public Context(State state) {
		this.state = state;
	}
	
	public void request() {
		state.handle(this);
	}
}

ConcreteStateA,具体状态类,每一个子类实现一个与Context相关的行为。在handle方法中设置ConcreteStateA的下一状态为ConcreteStateB。

public class ConcreteStateA implements State {

	@Override
	public void handle(Context context) {
		System.out.println("开始做A了");
		context.state = new ConcreteStateB();
	}

}

ConcreteStateB具体状态类

public class ConcreteStateB implements State {

	@Override
	public void handle(Context context) {
		System.out.println("开始做B了");
	}

}

测试类

public class StateTest {

	public static void main(String[] args) {
		Context context = new Context(new ConcreteStateA());//设置初始状态为ConcreteStateA
		
		context.request();
		context.request();
		context.request();
	}

}

结果:

3. 应用

就用状态模式改编一下上面关于工作状态的代码。直接上代码~

State类,抽象接口。

public interface State {

	void writeProgram(Work work);
}

Work类,就是上面的Context。定义了hour和finished,即需要不断变换的条件。维护了State接口。

public class Work {
	public State state;
	public int hour;
	public boolean finished = false;
	
	public Work(State state) {
		this.state = state;
	}
	
	public void request() {
		state.writeProgram(this);
	}
	
	public int getHour() {
		return hour;
	}
	
	public void setHour(int hour) {
		this.hour = hour;
	}

	public boolean isFinished() {
		return finished;
	}

	public void setFinished(boolean finished) {
		this.finished = finished;
	}

	public State getState() {
		return state;
	}

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

具体实现类A

public class MorningState implements State {

	@Override
	public void writeProgram(Work work) {
		int hour = work.getHour();
		if(hour<11) {
			System.out.println(hour+"点了,上午工作中");
		}else {
			work.setState(new NoonState());
			work.request();
		}
	}

}

具体实现类B

public class NoonState implements State {

	@Override
	public void writeProgram(Work work) {
		int hour = work.getHour();
		if(hour<13) {
			System.out.println(hour+"点了,中午休息中");
		}else {
			work.setState(new AfternooState());
			work.request();
		}
	}

}

具体实现类C

public class AfternooState implements State {

	@Override
	public void writeProgram(Work work) {
		int hour = work.getHour();
		if(hour<18) {
			System.out.println(hour+"点了,下午工作中");
		}else {
			work.setState(new EveningState());
			work.request();
		}
	}

}

具体实现类D

public class EveningState implements State {

	@Override
	public void writeProgram(Work work) {
		if(work.isFinished()) {
			work.setState(new RestState());
			work.request();
		} else {
			int hour = work.getHour();
			if(hour<21) {
				System.out.println(hour+"点了,夜晚加班中,累。。。");
			}else {
				work.setState(new SleepingState());
				work.request();
			}
		}
	}

}

具体实现类E

public class SleepingState implements State {

	@Override
	public void writeProgram(Work work) {
		if(work.isFinished()) {
			work.setState(new RestState());
			work.request();
		} else {
			int hour = work.getHour();
			System.out.println(hour+"点了,还在加班中,要睡着了。。。");
		}
	}

}

具体实现类F

public class RestState implements State {

	@Override
	public void writeProgram(Work work) {
		System.out.println(work.getHour()+"点了,下班了。");
	}

}

这里,我们将不同状态下所影响的行为分别封装在了子类ABCDEF中,实现具体的接口方法writeProgram。

测试类

public class StateTest {

	public static void main(String[] args) {
		Work work = new Work(new MorningState());//设置初始状态为上午
		work.setHour(9);
		work.request();
		work.setHour(12);
		work.request();
		work.setHour(15);
		work.request();
		
		//work.setFinished(true);
		
		work.setHour(20);
		work.request();
		work.setHour(23);
		work.request();
	}

}

结果:

如果将finished设置为true,则结果为:

完工~

4. 总结

  • 消除了庞大的if-else判断,降低了耦合性。
  • 将不同状态影响的行为分散到子类中去,增强了扩展性,当有新的状态行为时,只需要增加子类就行了。
  • 当一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为,这个时候可以考虑用状态模式。

 

 

累。。今天先写到这里,我看看,之后有空再补充一个例子进来。

 

写在最后:

本文主要是小猫看《大话设计模式》的笔记式的记录,方便以后查阅。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值