📄 statepattern.htm
字号:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<link rel="stylesheet" href="css/stdlayout.css" type="text/css">
<link rel="stylesheet" href="css/print.css" type="text/css">
<meta content="text/html; charset=gb2312" http-equiv="content-type">
<title>State 模式</title>
</head>
<body>
<h3><a href="http://caterpillar.onlyfun.net/GossipCN/index.html">From
Gossip@caterpillar</a></h3>
<h1><a href="CppGossip.html">Design Pattern: State 模式</a></h1>
如果您不了解TCP的连线方式,在看 <a href="GoF.htm"><span class="wikilink">Gof</span>
的书</a>介绍State模式时,大概会看得一头雾水吧!TCP的连线状态图,光是要了解就要花点精神了,它的连线状态很多,用来说明状态模式确实很适合,但不
适合教导初学模式的人。 <br>
<br>
由简单的开始会比较好理解状态模式的作用,先来看一个例子,如果您有一个只能顺时针转动的瓦斯开关,转动一次的状态为off、
small fire、medium fire与large
fire,您如何在程式中控制状态的变化与行为呢?一个最简单的方式就是用if..else或是switch流程来控制,例如:<br>
<ul>
<li> State.java
</li>
</ul>
<pre>public class State { <br> private int state;<br><br> public State() { <br> state = 0; <br> } <br><br> public void switchFire() { <br> if (state == 0) { <br> state = 1; <br> System.out.println( "small fire" ); <br> } else if (state == 1) { <br> state = 2; <br> System.out.println( "medium fire" ); <br> } else if (state == 2) { <br> state = 3; <br> System.out.println( "large fire" ); <br> } else { <br> state = 0; <br> System.out.println( "turning off" ); <br> } <br> } <br>} <br></pre>
<br>
<ul>
<li> Main.java
</li>
</ul>
<pre>public class Main { <br> public static void main(String[] args) { <br> State state = new State();<br><br> state.switchFire(); <br> state.switchFire(); <br> state.switchFire(); <br> state.switchFire(); <br> } <br>} <br></pre>
<br>
这个方法很简单,每个人都会,但如果您的状态变化并不是流水式的变化,而是像TCP连线状态一样,会是一个网络图的时候,用
if...else或switch来写的话,您的程式就会乱的不像话了;来考虑如何让物件控制自己的状态转换与所应表现的行为,这个程式可以这
样改写:<br>
<ul>
<li> IState.java
</li>
</ul>
<pre>public interface IState { <br> public void switchFire(FireSwitch sw); <br>} <br></pre>
<br>
<ul>
<li> OffState
</li>
</ul>
<pre>public class OffState implements IState { <br> public void switchFire(FireSwitch sw) { <br> sw.setState(new SmallState()); <br> System.out.println( "small fire" ); <br> } <br>} <br></pre>
<br>
<ul>
<li> SmallState.java
</li>
</ul>
<pre>public class SmallState implements IState { <br> public void switchFire(FireSwitch sw) { <br> sw.setState(new MediumState()); <br> System.out.println( "medium fire" ); <br> } <br>} <br></pre>
<br>
<ul>
<li> MediumState.java
</li>
</ul>
<pre>public class MediumState implements IState { <br> public void switchFire(FireSwitch sw) { <br> sw.setState(new LargeState()); <br> System.out.println( "large fire" ); <br> } <br>} <br></pre>
<br>
<ul>
<li> LargeState.java
</li>
</ul>
<pre>public class LargeState implements IState { <br> public void switchFire(FireSwitch sw) { <br> sw.setState(new OffState()); <br> System.out.println( "off fire" ); <br> } <br>} <br></pre>
<br>
<ul>
<li> FireSwitch.java
</li>
</ul>
<pre>public class FireSwitch { <br> private State current;<br><br> public FireSwitch() { <br> current = new OffState(); <br> }<br><br> public void setState(State s) { <br> current = s; <br> }<br><br> public void switchFire() { <br> current.switchFire(this); <br> }<br>} <br></pre>
<br>
<ul>
<li> Main.java
</li>
</ul>
<pre>public class Main { <br> public static void main(String[] args) { <br> FireSwitch fireSwitch = new FireSwitch();<br> fireSwitch.switchFire(); <br> fireSwitch.switchFire(); <br> fireSwitch.switchFire(); <br> fireSwitch.switchFire(); <br> } <br>} <br></pre>
<br>
程式执行结果与上一个例子是一样的,但这次并没有用流程控制来进行状态转换,而由物件自行控制自己的状态,与必须表现的行为,这个方式就是State 模式,将这个例子的 UML 类别结构画出就如下所示:<br>
<div style="text-align: center;"><img style="width: 454px; height: 211px;" alt="State" title="State" src="images/state-1.jpg"><br>
</div>
<br>
再进一步考虑开关可以顺时针与逆时针转动,这时如果您仍以if...else或switch来写,就会让流程显示复杂,来看看如何使用状态模式来撰
写: <br>
<ul>
<li> IState.java
</li>
</ul>
<pre>public interface IState { <br> public void switchClockWise(FireSwitch sw); <br> public void switchCountClock(FireSwitch sw); <br>} <br></pre>
<br>
<ul>
<li> OffState.java
</li>
</ul>
<pre>public class OffState implements IState { <br> public void switchClockWise(FireSwitch sw) { <br> sw.setState(new SmallState()); <br> System.out.println("small fire"); <br> }<br><br> public void switchCountClock(FireSwitch sw) { <br> sw.setState(new LargeState()); <br> System.out.println("large fire"); <br> } <br>} <br></pre>
<br>
<ul>
<li> SmallState.java
</li>
</ul>
<pre>public class SmallState implements IState { <br> public void switchClockWise(FireSwitch sw) { <br> sw.setState(new MediumState()); <br> System.out.println("medium fire"); <br> } <br><br> public void switchCountClock(FireSwitch sw) { <br> sw.setState(new OffState()); <br> System.out.println("off fire"); <br> } <br>} <br></pre>
<br>
<ul>
<li> MediumState.java
</li>
</ul>
<pre>public class MediumState implements IState { <br> public void switchClockWise(FireSwitch sw) { <br> sw.setState(new LargeState()); <br> System.out.println("large fire"); <br> }<br> <br> public void switchCountClock(FireSwitch sw) { <br> sw.setState(new SmallState()); <br> System.out.println("small fire"); <br> } <br>} <br></pre>
<br>
<ul>
<li> LargeState.java
</li>
</ul>
<pre>public class LargeState implements State { <br> public void switchClockWise(FireSwitch sw) { <br> sw.setState(new OffState()); <br> System.out.println("off fire"); <br> }<br><br> public void switchCountClock(FireSwitch sw) { <br> sw.setState(new MediumState()); <br> System.out.println("medium fire"); <br> } <br>} <br></pre>
<br>
<ul>
<li> FireSwitch.java
</li>
</ul>
<pre>public class FireSwitch { <br> private State current;<br><br> public FireSwitch() { <br> current = new OffState(); <br> }<br><br> public void setState(State s) { <br> current = s; <br> }<br><br> public void switchClockWise() { <br> current.switchClockWise(this); <br> }<br><br> public void switchCountClock() { <br> current.switchCountClock(this); <br> } <br>} <br></pre>
<br>
<ul>
<li> Main.java
</li>
</ul>
<pre>public class Main { <br> public static void main(String[] args) { <br> FireSwitch fireSwitch = new FireSwitch();<br><br> fireSwitch.switchClockWise(); <br> fireSwitch.switchClockWise(); <br> fireSwitch.switchClockWise(); <br> fireSwitch.switchClockWise(); <br><br> System.out.println();<br><br> fireSwitch.switchCountClock(); <br> fireSwitch.switchCountClock(); <br> fireSwitch.switchCountClock(); <br> fireSwitch.switchCountClock(); <br> } <br>} <br></pre>
<br>
接下来您可以任意的转动开关了,无论是顺时针转动或是逆时针转动,状态的转换都由物件自己来表现,这是双向状态转换下的例子,
如果一个状态可能转换至三个以上的状态,使用State模式就更可以看出它的好处了,就像Gof的TCP连线例子一样,如果您了解TCP连线,可以看看原
书是如何实现TCP连线之间的状态转换的。 <br>
<br>
State模式的UML结构图如下: <br>
<div style="text-align: center;"><img style="width: 383px; height: 217px;" alt="State" title="State" src="images/state-2.jpg"><br>
</div>
<br>
</body>
</html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -