采用C#泛型实现状态(State)模式


一、问题来源

目前时兴这样的应用:用户采用Jabber(一种开源即时通讯协议)客户端登录Jabber服务器,然后再经过MSN中转站,就可以与MSN用户通讯了。系统结构如下:

 

其中中转服务器实现协议翻译。假设存在这样一种情况,就是客户端和中转服务器采用的不是那种双向通讯,而是如Html这样单向通讯手段(假设不用Ajax),客户端没有存储能力,因此需要把信息存储在中转服务器的数据库中。中转服务器的流量很大,当接收到信息或者用户阅读未读信息后,不能实时进行数据库的Insert和Update操作,而是定期轮询,进行批量处理。

中转服务器将消息存储在消息容器中。线程模型如下:

 


主要有三类线程:

(1)服务器监听线程监听来自第三方服务器的数据包,解析成消息对象,存储在消息容器中。
(2)用户服务线程根据用户的请求,取出消息,发送给用户,同时改变消息的状态,如果消息为“未读”,则改变为“已读”。
(3)数据库同步线程定期检查所有消息,根据消息状态,判断客户端的消息状态是否和数据库中储存的状态一致,如果不一致,则进行Update操作,如果数据库中不存在,则进行Insert操作。

消息一共有五种状态:

          客户端是否已读    数据库中存储的状态      需要Update    需要Insert操作
状态1            已读                已读               否            否
状态2            已读                未读               是            否
状态3            未读                未读               否            否
状态4            未读                无                 否            是
状态5            已读                无                 否            是

用户阅读信息以及数据库同步操作可能导致用户状态改变。状态图如下:

 

二、实现

先给状态取名字:

    状态1:SReadedCReadedState
    状态2:SUnreadCReadState
    状态3:SUnreadCUnreadState
    状态4:SUnsavedCUnreadState
    状态5:SUnsavedCReadedState

根据《设计模式》书中的State模式,实现如下:


  1     public interface IMsgState
  2     {
  3         void MaskReaded(IMessage msg);  // 标为已读
  4         void MaskSaved(IMessage msg);   // 标为同步
  5         Boolean NeedInsert { get; }     // 是否Insert
  6         Boolean NeedUpdate { get;}      // 是否Update
  7         Boolean Readed { get;}          // 是否已读
  8     }
  9 
 10     public interface IMessage
 11     {
 12         void MaskReaded();
 13 
 14         void MaskSaved();
 15 
 16         Boolean NeedInsert { get; }
 17 
 18         Boolean NeedUpdate { get;}
 19 
 20         Boolean Readed { get;} 
 21 
 22         void ChangeState(IMsgState newState);
 23     }
 24 
 25     public class Message : IMessage
 26     {
 27         private IMsgState state;
 28 
 29         public Message(IMsgState initState)
 30         {
 31             state = initState;
 32         }
 33 
 34         #region IMessage 成员
 35 
 36         public void MaskReaded()
 37         {
 38             state.MaskReaded(this);
 39         }
 40 
 41         public void MaskSaved()
 42         {
 43             state.MaskSaved(this);
 44         }
 45 
 46         public bool NeedInsert
 47         {
 48             get { return state.NeedInsert; }
 49         }
 50 
 51         public bool NeedUpdate
 52         {
 53             get { return state.NeedUpdate; }
 54         }
 55 
 56         public bool Readed
 57         {
 58             get { return state.Readed; }
 59         }
 60 
 61         public void ChangeState(IMsgState newState)
 62         {
 63             this.state = newState;
 64         }
 65 
 66         #endregion
 67     }
 68 
 69     public class SReadedCReadedState : IMsgState
 70     {
 71         private static SReadedCReadedState instance = new SReadedCReadedState();
 72         public static SReadedCReadedState Instance
 73         {
 74             get { return instance; }
 75         }
 76 
 77         #region IMsgState 成员
 78 
 79         public void MaskReaded(IMessage msg)
 80         {
 81             msg.ChangeState(SReadedCReadedState.Instance);
 82         }
 83 
 84         public void MaskSaved(IMessage msg)
 85         {
 86             msg.ChangeState(SReadedCReadedState.Instance);
 87         }
 88 
 89         public bool NeedInsert
 90         {
 91             get { return false; }
 92         }
 93 
 94         public bool NeedUpdate
 95         {
 96             get { return false; }
 97         }
 98 
 99         public bool Readed
100         {
101             get { return true; }
102         }
103 
104         #endregion
105     }
106 
107     public class SUnreadCUnreadState : IMsgState
108     {
109         private static SUnreadCUnreadState instance = new SUnreadCUnreadState();
110         public static SUnreadCUnreadState Instance
111         {
112             get { return instance; }
113         }
114 
115         #region IMsgState 成员
116 
117         public void MaskReaded(IMessage msg)
118         {
119             msg.ChangeState(SUnreadCReadState.Instance);
120         }
121 
122         public void MaskSaved(IMessage msg)
123         {
124             msg.ChangeState(SUnreadCUnreadState.Instance);
125         }
126 
127         public bool NeedInsert
128         {
129             get { return false; }
130         }
131 
132         public bool NeedUpdate
133         {
134             get { return false; }
135         }
136 
137         public bool Readed
138         {
139             get { return false; }
140         }
141         #endregion
142     }
143 
144     public class SUnreadCReadState : IMsgState
145     {
146         private static SUnreadCReadState instance = new SUnreadCReadState();
147         public static SUnreadCReadState Instance
148         {
149             get { return instance; }
150         }
151 
152         #region IMsgState 成员
153 
154         public void MaskReaded(IMessage msg)
155         {
156             msg.ChangeState(SUnreadCReadState.Instance);
157         }
158 
159         public void MaskSaved(IMessage msg)
160         {
161             msg.ChangeState(SReadedCReadedState.Instance);
162         }
163 
164         public bool NeedInsert
165         {
166             get { return false; }
167         }
168 
169         public bool NeedUpdate
170         {
171             get { return true; }
172         }
173 
174         public bool Readed
175         {
176             get { return true; }
177         }
178 
179         #endregion
180     }
181 
182     public class SUnsavedCUnreadState : IMsgState
183     {
184         private static SUnsavedCUnreadState instance = new SUnsavedCUnreadState();
185         public static SUnsavedCUnreadState Instance
186         {
187             get { return instance; }
188         }
189 
190         #region IMsgState 成员
191 
192         public void MaskReaded(IMessage msg)
193         {
194             msg.ChangeState(SUnsavedCReadedState.Instance);
195         }
196 
197         public void MaskSaved(IMessage msg)
198         {
199             msg.ChangeState(SUnreadCUnreadState.Instance);
200         }
201 
202         public bool NeedInsert
203         {
204             get { return true; }
205         }
206 
207         public bool NeedUpdate
208         {
209             get { return false; }
210         }
211 
212         public bool Readed
213         {
214             get { return false; }
215         }
216 
217         #endregion
218     }
219 
220     public class SUnsavedCReadedState : IMsgState
221     {
222         private static SUnsavedCReadedState instance = new SUnsavedCReadedState();
223         public static SUnsavedCReadedState Instance
224         {
225             get { return instance; }
226         }
227 
228         #region IMsgState 成员
229 
230         public void MaskReaded(IMessage msg)
231         {
232             msg.ChangeState(SUnsavedCReadedState.Instance);
233         }
234 
235         public void MaskSaved(IMessage msg)
236         {
237             msg.ChangeState(SReadedCReadedState.Instance);
238         }
239 
240         public bool NeedInsert
241         {
242             get { return true; }
243         }
244 
245         public bool NeedUpdate
246         {
247             get { return false; }
248         }
249 
250         public bool Readed
251         {
252             get { return true; }
253         }
254 
255         #endregion
256 

假定消息存储在 IList<IMessage> msgs 之中,用户阅读操作:

1         void Read(IMessage msg)
2         {
3             //  do read, then:
4             msg.MaskReaded();
5         }
6 

同步操作:

 1         void Save()
 2         {
 3             foreach (IMessage msg in msgs)
 4             {
 5                 if (msg.NeedInsert)
 6                 {
 7                     // insert 
 8                 }
 9                 if (msg.NeedUpdate)
10                 {
11                     // update
12                 }
13 
14                 msg.MaskSaved();
15             }
16         }
17 

三、泛型实现

上面的实现太长了,并且状态相关的逻辑分布在各个类之中,相隔太远,容易写错。下面试试用泛型实现。

鉴于 C#2.0泛型不能用值作为参数类型(郁闷!!!!!!!!),因此首先需要把bool和false构造成类型:

 1     public interface IValueType<ValueType>
 2     {
 3         ValueType Value { get;}
 4     }
 5 
 6     public class TrueType : IValueType<bool>
 7     {
 8         public bool Value { get { return true; } }
 9     }
10 
11     public class FalseType : IValueType<bool>
12     {
13         public bool Value { get { return false; } }
14     }
15 

实现State模式:

  1     public interface IMsgState
  2     {
  3         void MaskReaded(IMessage msg);  // 标为已读
  4         void MaskSaved(IMessage msg);   // 标为同步
  5         Boolean NeedInsert { get; }     // 是否Insert
  6         Boolean NeedUpdate { get;}      // 是否Update
  7         Boolean Readed { get;}          // 是否已读
  8     }
  9 
 10     public interface IMessage
 11     {
 12         void MaskReaded();
 13 
 14         void MaskSaved();
 15 
 16         Boolean NeedInsert { get; }
 17 
 18         Boolean NeedUpdate { get;}
 19 
 20         Boolean Readed { get;}
 21 
 22         void ChangeState(IMsgState newState);
 23     }
 24 
 25     public class Message : IMessage
 26     {
 27         private IMsgState state;
 28 
 29         public Message(IMsgState initState)
 30         {
 31             state = initState;
 32         }
 33 
 34         #region IMessage 成员
 35 
 36         public void MaskReaded()
 37         {
 38             state.MaskReaded(this);
 39         }
 40 
 41         public void MaskSaved()
 42         {
 43             state.MaskSaved(this);
 44         }
 45 
 46         public bool NeedInsert
 47         {
 48             get { return state.NeedInsert; }
 49         }
 50 
 51         public bool NeedUpdate
 52         {
 53             get { return state.NeedUpdate; }
 54         }
 55 
 56         public bool Readed
 57         {
 58             get { return state.Readed; }
 59         }
 60 
 61         public void ChangeState(IMsgState newState)
 62         {
 63             this.state = newState;
 64         }
 65 
 66         #endregion
 67     }
 68 
 69     public class MsgState
 70         <MaskReadedToType, MaskSavedToType, 
 71         NeedInsertValueType, NeedUpdateValueType,
 72         ReadedValueType>
 73     : IMsgState
 74         where MaskReadedToType : IMsgState, new()
 75         where MaskSavedToType : IMsgState, new()
 76         where NeedInsertValueType : IValueType<bool>new()
 77         where NeedUpdateValueType : IValueType<bool>new()
 78         where ReadedValueType : IValueType<bool>new()
 79     {
 80         #region IMsgState 成员
 81 
 82         public void MaskReaded(IMessage msg)
 83         {
 84             msg.ChangeState(new MaskReadedToType());
 85         }
 86 
 87         public void MaskSaved(IMessage msg)
 88         {
 89             msg.ChangeState(new MaskSavedToType());
 90         }
 91 
 92         #endregion
 93 
 94         #region IMsgState 成员
 95 
 96 
 97         public bool NeedInsert
 98         {
 99             get { return new NeedInsertValueType().Value; } 
100         }
101 
102         public bool NeedUpdate
103         {
104             get { return new NeedUpdateValueType().Value; } 
105         }
106 
107         public bool Readed
108         {
109             get { return new ReadedValueType().Value; } 
110         }
111 
112         #endregion
113     }
114 
115     public class SReadedCReadedState:
116         MsgState<SReadedCReadedState, SReadedCReadedState, 
117         FalseType, FalseType, TrueType> { }
118 
119     public class SUnreadCUnreadState:
120         MsgState<SUnreadCReadState, SUnreadCUnreadState, 
121         FalseType, TrueType, FalseType> { }
122 
123     public class SUnreadCReadState:
124         MsgState<SUnreadCReadState, SReadedCReadedState, 
125         FalseType, FalseType, TrueType> { }
126 
127     public class SUnsavedCUnreadState:
128         MsgState<SUnsavedCReadedState, SUnreadCUnreadState, 
129         TrueType, FalseType, FalseType> { }
130 
131     public class SUnsavedCReadedState:
132         MsgState<SUnsavedCReadedState, SReadedCReadedState,
133         TrueType, FalseType, TrueType> { }
134 

其余操作同上:

 1         void Read(IMessage msg)
 2         {
 3             //  do read, then:
 4             msg.MaskReaded();
 5         }
 6 
 7         void Save()
 8         {
 9             foreach (IMessage msg in msgs)
10             {
11                 if (msg.NeedInsert)
12                 {
13                     // insert 
14                 }
15                 if (msg.NeedUpdate)
16                 {
17                     // update
18                 }
19 
20                 msg.MaskSaved();
21             }
22         }
23 

四、小结

由上可见,采用泛型实现的State模式代码量比不采用泛型实现的要少,更大的优点是,泛型实现中各种状态的定义比较短,这些定义可以放在一起,这样写起来也不容易写错,维护起来也比较简单。

(以上代码编译通过,逻辑上正确性与否我没验证----嘿嘿,事情讲清楚就可以了......)

作者:兽族的荣耀:xiaotie at gmail dot com; http://xiaotie.cnblogs.com

posted @ 2006-12-18 02:31  xiaotie  阅读(3912)  评论(3编辑  收藏  举报