博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
设计模式:浅谈行为模式State(C/C++ C#)
阅读量:4562 次
发布时间:2019-06-08

本文共 4168 字,大约阅读时间需要 13 分钟。

题外话:
    最近好忙啊,工作上还好说,主要是买了房子正在往房子里面塞东西,后悔房子买大了,要买这么多东西才能填满。
    今天重温了设计模式中的State,觉得有点心得想说说,通过C语言,C++和C#的几个例子,简单说说这种设计模式的应用和实际项目中的一些扩展,可能看到这大家都会说设计模式是面向对象的,C语言不是面向对象的,不是面向对象的语言就不可以用设计模式么,看看C语言的例子我们讨论一下。
    先看一下C#中的实现,这个例子是根据《设计模式》中给出的类设计视图的一个例子。
 1
None.gif
using
 System;
 2
None.gif
 3
None.gif
namespace
 State
 4
ExpandedBlockStart.gifContractedBlock.gif
dot.gif
{
 5InBlock.gif    //Abstract class of State
 6InBlock.gif    public abstract class State
 7ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
 8InBlock.gif        //Has only one Handle for presentation
 9InBlock.gif        public abstract void Handle();
10ExpandedSubBlockEnd.gif    }
11InBlock.gif
12InBlock.gif    //ConcreteClass of State
13InBlock.gif    public class ConcreteStateA : State
14ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
15InBlock.gif        public override void Handle()
16ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
17InBlock.gif            Console.WriteLine("A.Handle");
18ExpandedSubBlockEnd.gif        }
19ExpandedSubBlockEnd.gif    }
20InBlock.gif
21InBlock.gif    //Another ConcreteClass of State
22InBlock.gif    public class ConcreteStateB : State
23ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
24InBlock.gif        public override void Handle()
25ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
26InBlock.gif            Console.WriteLine("B.Handle");
27ExpandedSubBlockEnd.gif        }
28ExpandedSubBlockEnd.gif    }
29InBlock.gif
30InBlock.gif    //Main logic Class
31InBlock.gif    public class Context
32ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
33InBlock.gif        State state;
34InBlock.gif
35InBlock.gif        //Constructor of Context it initiate state to be State A
36InBlock.gif        public Context()
37ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
38InBlock.gif            state = new ConcreteStateA();
39ExpandedSubBlockEnd.gif        }
40InBlock.gif
41InBlock.gif        //Control of state
42InBlock.gif        public void ChangeState()
43ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
44InBlock.gif            state = new ConcreteStateB();
45ExpandedSubBlockEnd.gif        }
46InBlock.gif
47InBlock.gif        //Behavior of Object
48InBlock.gif        public void Request()
49ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
50InBlock.gif            state.Handle();
51ExpandedSubBlockEnd.gif        }
52ExpandedSubBlockEnd.gif    }
53InBlock.gif
54InBlock.gif    //Application Class 
55InBlock.gif    public class App
56ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
57InBlock.gif        public static void Main()
58ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
59InBlock.gif            Context context = new Context();
60InBlock.gif            context.Request();
61InBlock.gif            context.ChangeState();
62InBlock.gif            context.Request();
63ExpandedSubBlockEnd.gif        }
64ExpandedSubBlockEnd.gif    }
65ExpandedBlockEnd.gif}
运行的结果为:
A.Handle
B.Handle
分析:通过这个例子我们可以看出,我们将两个具体的类,通过状态的管理进行了解耦,而对于状态的管理或者说控制呢,我们放在了Context这个类中来进行,对于调用的应用程序,我们只需要维护一个state对象,通过调用Request()方法来实现调用,通过ChangeState()这个方法来改变context的状态,实现同样的的Request()方法调用不同的状态方法。
这是一个比较简单的例子,可以说其实是最简单的实现例子,看起来像对抽象,再看一个同样简单的C++的例子。
None.gif
#include 
"
stdafx.h
"
None.gif
None.gif#include 
<
iostream
>
None.gif#include 
<
string
>
None.gif
None.gif
using
 
namespace
 std;
None.gif
None.gif
class
 State
ExpandedBlockStart.gifContractedBlock.gif
dot.gif
{
InBlock.gif
public:
InBlock.gif    
virtual string response() = 0;
ExpandedBlockEnd.gif}
;
None.gif
None.gif
class
 Frog : 
public
 State
ExpandedBlockStart.gifContractedBlock.gif
dot.gif
{
InBlock.gif
public:
InBlock.gif    
string response()
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
return "Ribbet!!";
ExpandedSubBlockEnd.gif    }
;
ExpandedBlockEnd.gif}
;
None.gif
None.gif
class
 Prince : 
public
 State
ExpandedBlockStart.gifContractedBlock.gif
dot.gif
{
InBlock.gif
public:
InBlock.gif    
string response()
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
return "Darling";
ExpandedSubBlockEnd.gif    }
ExpandedBlockEnd.gif}
;
None.gif
None.gif
class
 Creature
ExpandedBlockStart.gifContractedBlock.gif
dot.gif
{
InBlock.gif    State
* state;
InBlock.gif
InBlock.gif
public:
InBlock.gif    Creature():state(
new Frog())
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{}
InBlock.gif
InBlock.gif    
void greet()
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        cout 
<< state->response() << endl;
ExpandedSubBlockEnd.gif    }
InBlock.gif
InBlock.gif    
void kiss()
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        delete state;
InBlock.gif        state 
= new Prince();
ExpandedSubBlockEnd.gif    }
ExpandedBlockEnd.gif}
;
None.gif
None.gif
int
 main()
ExpandedBlockStart.gifContractedBlock.gif
dot.gif
{
InBlock.gif    Creature creature;
InBlock.gif    creature.greet();
InBlock.gif    creature.kiss();
InBlock.gif    creature.greet();
ExpandedBlockEnd.gif}
这个实现是《C++编程思想 第2卷》 里面找到的一个例子,实现的内容几乎和前面一个例子相同,我稍微对代码进行了小的修改,可以看得出来,这是一个挺有意思的小例子,可以说是YY得很好,Kiss()之后青蛙变成了王子。看到这里我想大家应该对于state这个设计模式有了初步的了解,但是这个设计模式在实际的工作中是如何使用的呢,在什么时候我们才需要使用这样的设计模式呢,还有刚才说的C语言的问题是怎么回事呢,我们继续讨论。
先分析一下这个设计模式的适用范围吧,个人觉得这个设计模式很好,解决了很多问题,实际应用中也是非常常用的一个设计模式,但是并不是没有缺点或者说应该注意适用性的地方
第一个缺点就是可能会造成冗余,我们看前两个例子可以看得出来,状态的基类中只有一个方法,通常这是不太现实的,现实的是,可能会有很多很多方法,因为这个设计模式需要我们在基类列出所有的方法,不管这个方法是所有状态都会使用的,还是只有某个特殊状态才会使用的,这个时候不需要使用特定的方法的状态可能会产生冗余,虽然我们可以用空函数或者抛出异常来解决这个问题。对于10个以内的方法我觉得还好,如果上升到更高的数字级别的时候,也就是说不同的状态对应过多的方法的时候,需要另外的处理方式。
第二个是注意点,继续第一个问题,其实我们还可以使用另外一种方法来扩展这个设计模式。
首先用一个例子来更方面的说明,比如我们现在要做的模块或者说类的实例需要从很多其他模块中收各种各样的消息。
消息一共有100条,对应不同类型的消息,我们需要在我们这个模块的不同状态之间跳转,而且是无序的,然后再根据当前的状态,调用不用消息应该对应的各自的方法。假设我们有20各状态,也就是说,我需要写20个这样的状态类,每个状态类中需要写100中Handle(),这样算下来要写20000个实现,代码看起来估计会是很丑陋的,但是我还真见过这样写的,呵呵,数量级比这还高,最可怕的是着软件还卖出去了,怕怕。废话少说,这种情况我们怎么办呢,其实做一个简单的扩展就可以了。
分析这个实例,其实这20各状态中冗余是很大的,可能每个状态真正需要实现代码的只是对于10各消息的对应。我们找出这些对应的关系,将对应同类型消息的状态划分出来,单独作为一个状态,进入这个状态的时候,我们再在这个状态之中建立一个状态机,再次进行状态的检索,找到真正需要实现的内容,这样虽然我们将状态进行了嵌套,但是可以很好地解决代码冗余的问题。
最后再说说C语言的实现,其实并不是说设计模式只能用在面向对象程序设计当中,个人觉得设计模式只是一种方法论,是个非常灵活的东西,在我经历的项目中很多都是使用了状态机这个概念的C语言开发,觉得使用得很好,还是说到前面提到的一个概念,适用性的问题,面对大量的状态迁移,每种状态又对应多种实现要求的时候,这种设计模式还是非常有效的,设置从架构体系上来说都是非常简洁的一种方法。简单看一个例子:
None.gif
int32 (
*
Jump_table[][
3
])() 
=
ExpandedBlockStart.gifContractedBlock.gif
dot.gif
{
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{   /**//* Reading State */
ExpandedSubBlockStart.gifContractedSubBlock.gif        Function_Read,            
/**//* Read Request */
ExpandedSubBlockStart.gifContractedSubBlock.gif        Function_Null,            
/**//* Write Request */    
ExpandedSubBlockStart.gifContractedSubBlock.gif        Function_Null,            
/**//* Protect Request */
InBlock.gif
ExpandedSubBlockEnd.gif    }
,
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{   /**//* Writing State */
ExpandedSubBlockStart.gifContractedSubBlock.gif        Function_Null,            
/**//* Read Request */
ExpandedSubBlockStart.gifContractedSubBlock.gif        Function_Write,            
/**//* Write Request */    
ExpandedSubBlockStart.gifContractedSubBlock.gif        Function_Null,            
/**//* Protect Request */
ExpandedSubBlockEnd.gif    }
,
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{   /**//* Protecting State */
ExpandedSubBlockStart.gifContractedSubBlock.gif        Function_Null,            
/**//* Read Request */
ExpandedSubBlockStart.gifContractedSubBlock.gif        Function_Null,            
/**//* Write Request */    
ExpandedSubBlockStart.gifContractedSubBlock.gif        Function_Protect,s        
/**//* Protect Request */
ExpandedSubBlockEnd.gif    }
ExpandedBlockEnd.gif}
假设这是一个二维函数数组,使用State的设计思想,我们很用想到用各种状态对应各种不同的处理响应,其中Jump_table这个数组起到的作用就是管理这个函数数组的各个状态和对应的响应,剩下需要做的就是来实现各个函数的处理,和对这个函数数组做一个解析的工作,当不同的要求在不同的状态的时候正确找到应该响应的函数而已。
以上个人对于State设计模式的一点小见解,希望大家指点,呵呵,其实觉得23中设计模式并不是都是很常用的,不过这个State我可以说是天天在用啊,很方便的东西,嘿嘿。

转载于:https://www.cnblogs.com/kevin8000903/archive/2007/06/07/775482.html

你可能感兴趣的文章
.NET Core WebAPI IIS 部署问题
查看>>
SystemTap 静态探针安装包
查看>>
redis五种数据类型的使用
查看>>
浏览器全屏之requestFullScreen全屏与F11全屏
查看>>
软件包管理:rpm命令管理-安装升级与卸载
查看>>
旋转图像
查看>>
字符串中的数字(字符串、循环)
查看>>
15.select into
查看>>
Linux上安装Python3.5
查看>>
每日一小练——数值自乘递归解
查看>>
qq登陆错误提示
查看>>
bzoj 1192: [HNOI2006]鬼谷子的钱袋 思维 + 二进制
查看>>
没写完,没调完,咕咕咕的代码
查看>>
Android Studio使用技巧:导出jar包
查看>>
Problem E. TeaTree - HDU - 6430 (树的启发式合并)
查看>>
Kafka序列化和反序列化与示例
查看>>
win10下VS2010中文输入法切换为英文卡死
查看>>
retinex相关代码汇总
查看>>
Cortex-M3 异常返回值EXC_RETURN
查看>>
kettle 转换字段遇到问题(couldn't get row from result set)——摘
查看>>