采用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
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
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
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
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
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
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
版权所有,欢迎转载