【设计模式】第十五章:结构型模式-状态
发布于 2021-01-28 08:43
定义:
状态(State)模式的定义:对有状态的对象,把复杂的“判断逻辑”提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为,外界不需要知道状态及其变化情况。
使用场景:
①、一个对象的行为取决于它的状态,并且它必须在运行时根据状态改变它的行为。
②、代码中包含大量与对象状态有关的条件语句,例如,一个操作中含有庞大的分支语句 (if-else / switch-case) , 且这些分支依赖于该对象的状态。
比如:多线程存在 5 种状态,分别为新建状态、就绪状态、运行状态、阻塞状态和死亡状态,各个状态当遇到相关方法调用或事件触发时会转换到其他状态,其状态转换规律下图所示。
现在先定义一个抽象状态类(TheadState),然后为上图 所示的每个状态设计一个具体状态类,它们是新建状态(New)、就绪状态(Runnable )、运行状态(Running)、阻塞状态(Blocked)和死亡状态(Dead),每个状态中有触发它们转变状态的方法,环境类(ThreadContext)中先生成一个初始状态(New),并提供相关触发方法,下图所示是线程状态转换程序的结构图。
public class ThreadStateTest {
public static void main(String[] args) {
ThreadContext context = new ThreadContext();
context.start();
context.getCPU();
context.suspend();
context.resume();
context.getCPU();
context.stop();
}
}
/**
* 用来控制每个状态的流转
*/
class ThreadContext {
private ThreadState state;
ThreadContext() {
state = new New();
}
public ThreadState getState() {
return state;
}
public void start() {
((New) state).start();
if ("新建状态".equals(state.stateName)) {
state = new Runnable();
} else {
System.out.println("当前线程不是新建状态,不能调用start()方法.");
}
}
public void getCPU() {
((Runnable) state).getCPU();
if ("就绪状态".equals(state.stateName)) {
state = new Running();
} else {
System.out.println("当前线程不是就绪状态,不能获取CPU.");
}
}
public void suspend() {
((Running) state).suspend();
if ("运行状态".equals(state.stateName)) {
state = new Blocked();
} else {
System.out.println("当前线程不是运行状态,不能调用suspend()方法.");
}
}
public void stop() {
((Running) state).stop();
if ("运行状态".equals(state.stateName)) {
state = new Dead();
} else {
System.out.println("当前线程不是运行状态,不能调用stop()方法.");
}
}
public void resume() {
((Blocked) state).resume();
if ("阻塞状态".equals(state.stateName)) {
state = new Runnable();
} else {
System.out.println("当前线程不是阻塞状态,不能调用resume()方法.");
}
}
}
/**
* 抽象状态类:线程状态
*/
abstract class ThreadState {
//状态名
public String stateName;
}
/**
* 具体状态类:新建状态
*/
class New extends ThreadState {
public New() {
stateName = "新建状态";
System.out.println("当前线程处于:新建状态.");
}
public void start() {
System.out.print("调用start()方法-->");
}
}
/**
* 具体状态类:就绪状态
*/
class Runnable extends ThreadState {
public Runnable() {
stateName = "就绪状态";
System.out.println("当前线程处于:就绪状态.");
}
public void getCPU() {
System.out.print("获得CPU时间-->");
}
}
/**
* 具体状态类:运行状态
*/
class Running extends ThreadState {
public Running() {
stateName = "运行状态";
System.out.println("当前线程处于:运行状态.");
}
public void suspend() {
System.out.print("调用suspend()方法-->");
}
public void stop() {
System.out.print("调用stop()方法-->");
}
}
/**
* 具体状态类:阻塞状态
*/
class Blocked extends ThreadState {
public Blocked() {
stateName = "阻塞状态";
System.out.println("当前线程处于:阻塞状态.");
}
public void resume() {
System.out.print("调用resume()方法-->");
}
}
/**
* 具体状态类:死亡状态
*/
class Dead extends ThreadState {
public Dead() {
stateName = "死亡状态";
System.out.println("当前线程处于:死亡状态.");
}
}
程序运行结果如下:
当前线程处于:新建状态.
调用start()方法-->当前线程处于:就绪状态.
获得CPU时间-->当前线程处于:运行状态.
调用suspend()方法-->当前线程处于:阻塞状态.
调用resume()方法-->当前线程处于:就绪状态.
获得CPU时间-->当前线程处于:运行状态.
调用stop()方法-->当前线程处于:死亡状态.
策略模式与状态模式区别:
1、状态模式重点在各状态之间的切换,从而做不同的事情;而策略模式更侧重于根据具体情况选择策略,并不涉及切换。
2、状态模式不同状态下做的事情不同,而策略模式做的都是同一件事。例如,聚合支付平台,有支付宝、微信支付、银联支付,虽然策略不同,但最终做的事情都是支付,也就是说他们之间是可替换的。反观状态模式,各个状态的同一方法做的是不同的事,不能互相替换。
3、状态模式封装了对象的状态,而策略模式封装算法或策略。因为状态是跟对象密切相关的,它不能被重用;而策略模式通过从Context中分离出策略或算法,我们可以重用它们。
4、在状态模式中,每个状态通过持有Context的引用,来实现状态转移;但是每个策略都不持有Context的引用,它们只是被Context使用。
5、状态模式将各个状态所对应的操作分离开来,即对于不同的状态,由不同的子类实现具体操作,不同状态的切换由子类实现,当发现传入参数不是自己这个状态所对应的参数,则自己给Context类切换状态;这种转换是"自动","无意识"的。状态模式允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。而策略模式是直接依赖注入到Context类的参数进行策略选择,不存在切换状态的操作。
6、策略模式的客户端必须对所有的策略类相当了解,明确当前场景下各种策略的利弊,权衡在当前场景下应该使用哪种策略,也就是是说策略类对客户端是暴露的,策略是外界给的,策略怎么变,是调用者考虑的事情,系统只是根据所给的策略做事情。
状态模式依赖于其状态的变化时其内部的行为发生变化,将动作委托到代表当前状态的对象,对外表现为类发生了变化。状态是系统自身的固有的,由系统本身控制,调用者不能直接指定或改变系统的状态转移。
本文来自网络或网友投稿,如有侵犯您的权益,请发邮件至:aisoutu@outlook.com 我们将第一时间删除。
相关素材