2021-07-29

状态模式(学习笔记)

  1. 意图

  允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类

  2. 动机

  状态模式与有限状态机的概念紧密相关。其主要思想是程序在任意时刻仅可处于几种有限的状态中。在任何一个特定状态中,程序的行为都不相同,且可瞬间从一个状态切换到另一个状态。不过,根据当前状态,程序可能会切换到另外一种状态,也可能会保持当前状态不变。这些数量有限且预先定义的状态切换规则被称为转移  

  假如你有一个 文档Document类。文档可能会处于草稿Draft 、 ​审阅中Moderation和 已发布Published三种状态中的一种。文档的 publish发布方法在不同状态下的行为略有不同:

  • 处于草稿状态时,它会将文档转移到审阅中状态
  • 处于审阅中状态时,如果当前用户是管理员,会公开发布文档
  • 处于已发布状态时,它不会进行任何操作

     

  状态机通常由众多条件运算符( if或 switch )实现,可根据对象的当前状态选择相应的行为。"状态" 通常只是对象中的一组成员变量值。如下伪码所示:

class Document is field state: string // ... method publish() is  switch (state)   "draft":    state = "moderation"    break   "moderation":    if (currentUser.role == 'admin')     state = "published"    break   "published":    // 什么也不做。    break // ...

  当我们逐步在文档类中添加更多状态和依赖于状态的行为后,基于条件语句的状态机就会暴露其最大的弱点。为了能根据当前状态选择完成相应行为的方法,绝大部分方法中会包含复杂的条件语句。修改其转换逻辑可能会涉及到修改所有方法中的状态条件语句,导致代码的维护工作非常艰难。这个问题会随着项目进行变得越发严重。我们很难在设计阶段预测到所有可能的状态和转换。随着时间推移,最初仅包含有限条件语句的简洁状态机可能会变的臃肿而难以维护。  

  状态模式建议为对象的所有可能状态新建一个类,然后将所有状态的对应行为抽取到这些类中。原始对象被称为上下文(context),它并不会自行实现所有行为,而是会保存一个指向表示当前状态的状态对象的引用,且将所有与状态相关的工作委派给该对象

     

  如需将上下文转换为另外一种状态,则需将当前活动的状态对象替换为另外一个代表新状态的对象。采用这种方式是有前提的:所有状态类都必须遵循同样的接口,而且上下文必须仅通过接口与这些对象进行交互。这个结构可能看上去与策略模式相似,但有一个关键性的不同——在状态模式中,特定状态知道其他所有状态的存在,且能触发从一个状态到另一个状态的转换;策略则几乎完全不知道其他策略的存在

  3. 适用性

  • 一个对象的行为取决于它的状态,并且它必须在运行时根据状态改变它的行为
  • 一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态,这个状态通常用一个或多个枚举常量表示。通常,有多个操作包含这一相同的条件结构。State模式将每一个条件分支放入一个独立的类中。这样可以根据对象自身的情况将对象的状态作为一个对象,这一对象可以不依赖于其他对象而独立变化

  4. 结构

         

  5. 效果

  1. 通过消除臃肿的状态机条件语句简化上下文代码

  2. 将与特定状态相关的行为局部化,并且将不同状态的行为分割开来(单一职责原则)

  3. 无需修改已有状态类和上下文就能引入新状态(开闭原则)

  4. State对象可被共享 各Context对象可以共享一个State对象。当状态以这种方式被共享时,他们必然是没有内部状态而只有行为的轻量级对象(Flyweight)

  6. 代码实现  

  本例中,状态模式允许媒体播放器根据当前的回放状态进行不同的控制行为。播放器主类包含一个指向状态对象的引用,它将完成播放器的绝大部分工作。某些行为可能会用一个状态对象替换另一个状态对象,改变播放器对用户交互的回应方式。

  states/State.java: 通用状态接口

package state.states;import state.ui.Player;/** * @author GaoMing * @date 2021/7/26 - 8:02 */public abstract class State { Player player; /**  * Context passes itself through the state constructor. This may help a  * state to fetch some useful context data if needed.  */ State(Player player) {  this.player = player; } public abstract String onLock(); public abstract String onPlay(); public abstract String onNext(); public abstract String onPrevious();}

  states/LockedState.java

package state.states;import state.ui.Player;/** * @author GaoMing * @date 2021/7/26 - 8:04 * Concrete states provide the special implementation for all interface methods. */public class LockedState extends State{ LockedState(Player player) {  super(player);  player.setPlaying(false); } @Override public String onLock() {  if (player.isPlaying()) {   player.changeState(new ReadyState(player));   return "Stop playing";  } else {   return "Locked...";  } } @Override public String onPlay() {  player.changeState(new ReadyState(player));  return "Ready"; } @Override public String onNext() {  return "Locked..."; } @Override public String onPrevious() {  return "Locked..."; }}

  states/ReadyState.java

package state.states;import state.ui.Player;/** * @author GaoMing * @date 2021/7/26 - 8:06 * They can also trigger state transitions in the context. */public class ReadyState extends State{ public ReadyState(Player player) {  super(player); } @Override public String onLock() {  player.changeState(new LockedState(player));  return "Locked..."; } @Override public String onPlay() {  String action = player.startPlayback();  player.changeState(new PlayingState(player));  return action; } @Override public String onNext() {  return "Locked..."; } @Override public String onPrevious() {  return "Locked..."; }}

  states/PlayingState.java

package state.states;import state.ui.Player;/** * @author GaoMing * @date 2021/7/26 - 8:06 */public class PlayingState extends State{ PlayingState(Player player) {  super(player); } @Override public String onLock() {  player.changeState(new LockedState(player));  player.setCurrentTrackAfterStop();  return "Stop playing"; } @Override public String onPlay() {  player.changeState(new ReadyState(player));  return "Paused..."; } @Override public String onNext() {  return player.nextTrack(); } @Override public String onPrevious() {  return player.previousTrack(); }}

  ui/Player.java: 播放器的主要代码

package state.ui;import state.states.ReadyState;import state.states.State;import java.util.ArrayList;import java.util.List;/** * @author GaoMing * @date 2021/7/26 - 8:03 */public class Player { private State state; private boolean playing = false; private List<String> playlist = new ArrayList<>(); private int currentTrack = 0; public Player() {  this.state = new ReadyState(this);  setPlaying(true);  for (int i = 1; i <= 12; i++) {   playlist.add("Track " + i);  } } public void changeState(State state) {  this.state = state; } public State getState() {  return state; } public void setPlaying(boolean playing) {  this.playing = playing; } public boolean isPlaying() {  return playing; } public String startPlayback() {  return "Playing " + playlist.get(currentTrack); } public String nextTrack() {  currentTrack++;  if (currentTrack > playlist.size() - 1) {   currentTrack = 0;  }  return "Playing " + playlist.get(currentTrack); } public String previousTrack() {  currentTrack--;  if (currentTrack < 0) {   currentTrack = playlist.size() - 1;  }  return "Playing " + playlist.get(currentTrack); } public void setCurrentTrackAfterStop() {  this.currentTrack = 0; }}

  ui/UI.java: 播放器的 GUI

package state.ui;import javax.swing.*;import java.awt.*;/** * @author GaoMing * @date 2021/7/26 - 8:07 */public class UI { private Player player; private static JTextField textField = new JTextField(); public UI(Player player) {  this.player = player; } public void init() {  JFrame frame = new JFrame("Test player");  frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  JPanel context = new JPanel();  context.setLayout(new BoxLayout(context, BoxLayout.Y_AXIS));  frame.getContentPane().add(co......

原文转载:http://www.shaoqun.com/a/892281.html

跨境电商:https://www.ikjzd.com/

let go:https://www.ikjzd.com/w/825

雨果网:https://www.ikjzd.com/w/1307

e票联:https://www.ikjzd.com/w/1452


1.意图  允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类  2.动机  状态模式与有限状态机的概念紧密相关。其主要思想是程序在任意时刻仅可处于几种有限的状态中。在任何一个特定状态中,程序的行为都不相同,且可瞬间从一个状态切换到另一个状态。不过,根据当前状态,程序可能会切换到另外一种状态,也可能会保持当前状态不变。这些数量有限且预先定义的状态切换规则被称为转移    假如你
马士基集团:https://www.ikjzd.com/w/1296
四川温泉旅游线路推荐_四川泡温泉哪里好_四川哪里有温泉 :http://www.30bags.com/a/414193.html
四川温泉有哪些?四川温泉旅游线路推荐:http://www.30bags.com/a/429675.html
四川温泉有哪些?四川温泉旅游线路推荐_峨眉山旅游攻略_峨眉山旅游景点:http://www.30bags.com/a/415422.html
四川汶川多地泥石流灾害 2人失联3人被困:http://www.30bags.com/a/424909.html
我想吃你的水蜜桃 一边吃早餐一边做:http://lady.shaoqun.com/a/247933.html
公捡筷子时我故意把腿张开 他的手在课桌下揉捏着她:http://www.30bags.com/m/a/249838.html
口述:公公竟然偷听我和丈夫爱爱公公老公爱爱:http://www.30bags.com/m/a/249528.html
深圳宝安科技馆8月展览汇总(持续更新):http://www.30bags.com/a/517601.html
2021时尚深圳展蝶讯馆展览好看吗:http://www.30bags.com/a/517602.html
2021时尚深圳蝶讯馆观展攻略:http://www.30bags.com/a/517603.html
深圳欢乐谷夏浪音乐节有朱星杰吗:http://www.30bags.com/a/517604.html

No comments:

Post a Comment