| 编辑推荐: | 
                                   
                                   
                                     
                                      本文介绍如何采用C#泛型实现状态(State)模式,希望对您的学习有所帮助。   
                                   
                                      本文来自cnblogs,由火龙果软件Linda编辑、推荐。 | 
                                   
                                  | 
                             
                           
                           
                          一、问题来源 
                          目前时兴这样的应用:用户采用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模式代码量比不采用泛型实现的要少,更大的优点是,泛型实现中各种状态的定义比较短,这些定义可以放在一起,这样写起来也不容易写错,维护起来也比较简单。 
 
                            |