【设计模式】第十五章:结构型模式-状态

发布于 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 我们将第一时间删除。

相关素材