前传:
一个类内部存在多个条件分支时,你应该想一下,是不是可以用状态模式给替换。
那什么是状态模式呀?
state 把对象的内部状态独立出来,封装内部状态变化。
实现:
那怎么封装呀?想想应该有两个类:主类,辅助类(即状态类)。
主类开始得有一个状态呀。激发状态变化,但实现状态变化的细节,却通过状态类来实现。
状态类修改主类的状态。根据主类的当前状态指定主类(跳转)到下一状态类。
主类和状态类的双向互动:主类通过函数推动状态类变化;状态类负责修改主类的状态。
用户根本就不知道状态类的存在。只有程序员才知道具体的实现。(这也是传说中的“封装”)
关键词:
封装 内部状态
网上一个兄弟的例子很说明问题:
<p style="margin: 10px auto; padding-top: 0px; padding-bottom: 0px; color: rgb(51, 51, 51); font-family: verdana, Arial, Helvetica, sans-serif; font-size: 14px; line-height: 25px; ">电灯有两个状态,开(亮)与关(不亮),下面就用状态模式来实现对电灯的控制。</p><p style="margin: 10px auto; padding-top: 0px; padding-bottom: 0px; color: rgb(51, 51, 51); font-family: verdana, Arial, Helvetica, sans-serif; font-size: 14px; line-height: 25px; "> 类图</p><p style="margin: 10px auto; padding-top: 0px; padding-bottom: 0px; color: rgb(51, 51, 51); font-family: verdana, Arial, Helvetica, sans-serif; font-size: 14px; line-height: 25px; "> <img src="http://pic002.cnblogs.com/images/2012/155937/2012071614433983.png" alt="" style="margin: 0px; padding: 0px; border: 0px; " /></p><p style="margin: 10px auto; padding-top: 0px; padding-bottom: 0px; color: rgb(51, 51, 51); font-family: verdana, Arial, Helvetica, sans-serif; font-size: 14px; line-height: 25px; "> 实现代码</p><div class="cnblogs_code" style="margin: 5px 0px; padding: 5px; background-color: rgb(245, 245, 245); font-family: 'Courier New' !important; border: 1px solid rgb(204, 204, 204); overflow: auto; "><div class="cnblogs_code_toolbar" style="margin: 5px 0px 0px; padding: 0px; "><span class="cnblogs_code_copy" style="margin: 0px; padding: 0px 5px 0px 0px; line-height: 1.8; "><a target=_blank href="http://www.cnblogs.com/wangjq/archive/2012/07/16/2593485.html" title="复制代码" style="margin: 0px; padding: 0px; text-decoration: none; color: rgb(0, 0, 0); border: none !important; "><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" style="margin: 0px; padding: 0px; border: none !important; " /></a></span></div><pre style="margin-top: 0px; margin-bottom: 0px; padding: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: 'Courier New' !important; "> <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(128, 128, 128); ">///</span> <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(128, 128, 128); "><summary></span> <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(128, 128, 128); ">///</span><span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(0, 128, 0); "> 电灯类,对应模式中的Context类 </span><span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(128, 128, 128); ">///</span> <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(128, 128, 128); "></summary></span> <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(0, 0, 255); ">public</span> <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(0, 0, 255); ">class</span><span style="margin: 0px; padding: 0px; line-height: 1.8; "> Light { </span><span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(0, 0, 255); ">private</span><span style="margin: 0px; padding: 0px; line-height: 1.8; "> LightState state; </span><span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(0, 0, 255); ">public</span><span style="margin: 0px; padding: 0px; line-height: 1.8; "> Light(LightState state) { </span><span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(0, 0, 255); ">this</span>.state =<span style="margin: 0px; padding: 0px; line-height: 1.8; "> state; } </span><span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(128, 128, 128); ">///</span> <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(128, 128, 128); "><summary></span> <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(128, 128, 128); ">///</span><span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(0, 128, 0); "> 按下电灯开关 </span><span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(128, 128, 128); ">///</span> <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(128, 128, 128); "></summary></span> <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(0, 0, 255); ">public</span> <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(0, 0, 255); ">void</span><span style="margin: 0px; padding: 0px; line-height: 1.8; "> PressSwich() { state.PressSwich(</span><span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(0, 0, 255); ">this</span><span style="margin: 0px; padding: 0px; line-height: 1.8; ">); } </span><span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(0, 0, 255); ">public</span><span style="margin: 0px; padding: 0px; line-height: 1.8; "> LightState State { </span><span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(0, 0, 255); ">get</span> { <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(0, 0, 255); ">return</span><span style="margin: 0px; padding: 0px; line-height: 1.8; "> state; } </span><span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(0, 0, 255); ">set</span> { state =<span style="margin: 0px; padding: 0px; line-height: 1.8; "> value; } } } </span><span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(128, 128, 128); ">///</span> <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(128, 128, 128); "><summary></span> <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(128, 128, 128); ">///</span><span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(0, 128, 0); "> 抽象的电灯状态类,相当于State类 </span><span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(128, 128, 128); ">///</span> <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(128, 128, 128); "></summary></span> <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(0, 0, 255); ">public</span> <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(0, 0, 255); ">abstract</span> <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(0, 0, 255); ">class</span><span style="margin: 0px; padding: 0px; line-height: 1.8; "> LightState { </span><span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(0, 0, 255); ">public</span> <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(0, 0, 255); ">abstract</span> <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(0, 0, 255); ">void</span><span style="margin: 0px; padding: 0px; line-height: 1.8; "> PressSwich(Light light); } </span><span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(128, 128, 128); ">///</span> <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(128, 128, 128); "><summary></span> <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(128, 128, 128); ">///</span><span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(0, 128, 0); "> 具体状态类, 开 </span><span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(128, 128, 128); ">///</span> <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(128, 128, 128); "></summary></span> <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(0, 0, 255); ">public</span> <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(0, 0, 255); ">class</span><span style="margin: 0px; padding: 0px; line-height: 1.8; "> On : LightState { </span><span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(128, 128, 128); ">///</span> <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(128, 128, 128); "><summary></span> <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(128, 128, 128); ">///</span><span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(0, 128, 0); "> 在开状态下,按下开关则切换到关的状态。 </span><span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(128, 128, 128); ">///</span> <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(128, 128, 128); "></summary></span> <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(128, 128, 128); ">///</span> <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(128, 128, 128); "><param name="light"></param></span> <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(0, 0, 255); ">public</span> <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(0, 0, 255); ">override</span> <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(0, 0, 255); ">void</span><span style="margin: 0px; padding: 0px; line-height: 1.8; "> PressSwich(Light light) { Console.WriteLine(</span><span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(128, 0, 0); ">"</span><span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(128, 0, 0); ">Turn off the light.</span><span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(128, 0, 0); ">"</span><span style="margin: 0px; padding: 0px; line-height: 1.8; ">); light.State </span>= <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(0, 0, 255); ">new</span><span style="margin: 0px; padding: 0px; line-height: 1.8; "> Off(); } } </span><span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(128, 128, 128); ">///</span> <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(128, 128, 128); "><summary></span> <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(128, 128, 128); ">///</span><span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(0, 128, 0); "> 具体状态类,关 </span><span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(128, 128, 128); ">///</span> <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(128, 128, 128); "></summary></span> <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(0, 0, 255); ">public</span> <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(0, 0, 255); ">class</span><span style="margin: 0px; padding: 0px; line-height: 1.8; "> Off: LightState { </span><span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(128, 128, 128); ">///</span> <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(128, 128, 128); "><summary></span> <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(128, 128, 128); ">///</span><span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(0, 128, 0); "> 在关状态下,按下开关则打开电灯。 </span><span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(128, 128, 128); ">///</span> <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(128, 128, 128); "></summary></span> <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(128, 128, 128); ">///</span> <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(128, 128, 128); "><param name="light"></param></span> <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(0, 0, 255); ">public</span> <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(0, 0, 255); ">override</span> <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(0, 0, 255); ">void</span><span style="margin: 0px; padding: 0px; line-height: 1.8; "> PressSwich(Light light) { Console.WriteLine(</span><span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(128, 0, 0); ">"</span><span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(128, 0, 0); ">Turn on the light.</span><span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(128, 0, 0); ">"</span><span style="margin: 0px; padding: 0px; line-height: 1.8; ">); light.State </span>= <span style="margin: 0px; padding: 0px; line-height: 1.8; color: rgb(0, 0, 255); ">new</span><span style="margin: 0px; padding: 0px; line-height: 1.8; "> On(); } }</span>
客户端代码
class Program { static void Main(string[] args) { // 初始化电灯,原始状态为关 Light light = new Light(new Off()); // 第一次按下开关,打开电灯 light.PressSwich(); // 第二次按下开关,关闭电灯 light.PressSwich(); Console.Read(); } }