这几天,接手一个同事的代码,关于微信接口开发的,那一堆的 if,看得哥蛋痛了,这个毛病也是很多新手容易犯的,所以特地把这次重构写出来。
下面来我们看看这个代码的问题所在,if else 里面的代码块逻辑,不好改,使得它的重用性为 0,并且难以阅读。当然,如果 if 只有一两个,或者3个,这样写是问题不大的。
但是如果多了,这种代码便会让维护变得困难起来。
if (strMsgType == "text") { textContentClient = rootElement.SelectSingleNode("Content").InnerText; strResult = SetMsgType_Text(strClientName, textContentClient, db, strServerName, Identity); System.Diagnostics.Trace.WriteLine(strResult); return Content(strResult); } else if (strMsgType == "event") { string eventType = rootElement.SelectSingleNode("Event").InnerText.ToLower(); if (eventType == "subscribe") { string keyCode = ""; if (rootElement.SelectSingleNode("EventKey") != null) keyCode = rootElement.SelectSingleNode("EventKey").InnerText.ToLower(); strResult = FormatEventSubscribe(keyCode); RecordReplyMessage(); return Content(strResult); } else if (eventType == "scan") { string keyCode = rootElement.SelectSingleNode("EventKey").InnerText.ToLower(); var outLetName = "欢迎关注"; var outletDB = ShoppingContext.CreateInstance(Identity); var outLetModel = outletDB.Outlets.FirstOrDefault(o => o.SceneId == Int32.Parse(keyCode)); if (outLetModel != null) outLetName += outLetModel.Name; return Content(GetTextTemp(strClientName, strServerName, outLetName)); } else if (eventType == "click") { string keyCode = rootElement.SelectSingleNode("EventKey").InnerText.ToLower(); strResult = FomatMenuMessage(keyCode); return Content(strResult); } else if (eventType == "unsubscribe") { var subIds = db.ReplyRecords.Where(r => r.FromOpenId == this.ClientId.ToString() && r.EMessType == EEventType.Subscribe.ToString() && r.KeyWord != null).Select(o => o.KeyWord).ToArray(); var unSubIds = db.ReplyRecords.Where(r => r.FromOpenId == this.ClientId.ToString() && r.EMessType == EEventType.Unsubscribe.ToString() && r.KeyWord != null).Select(o => o.KeyWord).ToArray(); var SencesId = ""; foreach (var k in subIds) { if (!unSubIds.Contains(k)) { this.ReplyModel.KeyWord = k; break; } } this.ReplyModel.EMessType = EEventType.Unsubscribe.ToString(); RecordReplyMessage(); } } else if (strMsgType.ToLower() == "location") { string strLocation_X = rootElement.SelectSingleNode("Location_X").InnerText; string strLocation_Y = rootElement.SelectSingleNode("Location_Y").InnerText; strResult = FormatOutLetLBS(double.Parse(strLocation_X), double.Parse(strLocation_Y), 10); //strResult = FormatTextMessage(strLocation_X + "|" + strLocation_Y); return Content(strResult); } else if (strMsgType.ToLower() == "image") { string strImgUrl = rootElement.SelectSingleNode("PicUrl").InnerText; }
一种比较好的处理方法就是把语句块内的代码抽出来,写成函数,如下面所示:
public class MessageProcesser { public ReplyMessage Process(string xml) { var msg = PostMessage.FromXml(xml); switch (msg.MsgType) { case Models.PostMessageType.Event: var eventType = ((EventMessage)msg).Event; switch (eventType) { case EventType.Click: return ProcessClickEvent((ClickEvent)msg); case EventType.Location: return ProcessLocationEvent((LocationEvent)msg); case EventType.Scan: return ProcessScanEvent((ScanEvent)msg); case EventType.Subscribe: return ProcessSubscribeEvent((SubscribeEvent)msg); case EventType.Unsubscribe: return ProcessUnsubscribeEvent((UnsubscribeEvent)msg); } break; case Models.PostMessageType.Image: return ProcessImageMessage((ImageMessage)msg); case Models.PostMessageType.Link: return ProcessLinkMessage((LinkMessage)msg); case Models.PostMessageType.Location: return ProcessLocationMessage((LocationMessage)msg); case Models.PostMessageType.Text: return ProcessTextMessage((TextMessage)msg); case Models.PostMessageType.Video: return ProcessVideoMessage((VideoMessage)msg); case Models.PostMessageType.Voice: return ProcessVoiceMessage((VoiceMessage)msg); } return null; } protected virtual ReplyMessage ProcessClickEvent(ClickEvent msg) { return DefaultProcess(msg); } protected virtual ReplyMessage ProcessLocationEvent(LocationEvent msg) { return DefaultProcess(msg); } protected virtual ReplyMessage ProcessScanEvent(ScanEvent msg) { return DefaultProcess(msg); } protected virtual ReplyMessage ProcessSubscribeEvent(SubscribeEvent msg) { return DefaultProcess(msg); } protected virtual ReplyMessage ProcessUnsubscribeEvent(UnsubscribeEvent msg) { return DefaultProcess(msg); } protected virtual ReplyMessage ProcessImageMessage(ImageMessage msg) { return DefaultProcess(msg); } protected virtual ReplyMessage ProcessLinkMessage(LinkMessage msg) { return DefaultProcess(msg); } protected virtual ReplyMessage ProcessLocationMessage(LocationMessage msg) { return DefaultProcess(msg); } protected virtual ReplyMessage ProcessTextMessage(TextMessage msg) { return DefaultProcess(msg); } protected virtual ReplyMessage ProcessVideoMessage(VideoMessage msg) { return DefaultProcess(msg); } protected virtual ReplyMessage ProcessVoiceMessage(VoiceMessage msg) { return DefaultProcess(msg); } protected virtual ReplyMessage DefaultProcess(PostMessage msg) { var reply = new TextReply(msg); if (msg.MsgType == PostMessageType.Event) { reply.Content = string.Format("{0} event is not processed.", ((EventMessage)msg).Event); } else { reply.Content = string.Format("{0} message is not processed.", msg.MsgType); } return reply; } }
在使用的时候,继承上面的类就行了。
public class MyMessageProcesser : WeiXin.MessageProcesser { public MyMessageProcesser() { } protected override ReplyMessage ProcessSubscribeEvent(SubscribeEvent msg) { var reply = new TextReply(msg); reply.Content = "你好,欢迎关注"; return reply; } protected override ReplyMessage ProcessUnsubscribeEvent(UnsubscribeEvent msg) { var reply = new TextReply(msg); reply.Content = "取消关注"; return reply; } }
欢迎讨论,欢迎板砖。
=======================================================
有朋友说,我只是把 if 换成了 switch,这个没错,但更重要的是,换成了一个可重写方法的类。
有朋友说,使用命令模式会不会更好点。是这样的,因为是微信的接口,以后就算是增加,也是很少会发生的,并且要作的改动也不多。所以不想变得太复杂了。现在是 if 内的语句块需要变动,因为要面对不同的用户,他们的处理都是不同的。