面對滿屏的 if-else 巢狀結構,維護者往往「蛋痛」不已。本文通過微信接口消息處理的真實重構案例,展示如何運用策略模式與多態分發,將千行巨型函數拆解為清晰可擴展的類結構。
if (strMsgType == "text") {
// ... 處理文本消息
}
else if (strMsgType == "event") {
string eventType = rootElement.SelectSingleNode("Event").InnerText.ToLower();
if (eventType == "subscribe") {
// ... 處理訂閱
}
else if (eventType == "scan") {
// ... 處理掃碼
}
else if (eventType == "click") {
// ... 處理點擊
}
else if (eventType == "unsubscribe") {
// ... 處理取消訂閱,邏輯極其複雜
}
}
else if (strMsgType.ToLower() == "location") { ... }
else if (strMsgType.ToLower() == "image") { ... }
// 更多類型...
痛點:
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 方法,子類可覆寫擴展
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;
}
}
PostMessage.FromXml(xml) 統一解析 XML 為強類型對象樹switch (msg.MsgType)、內層 switch (eventType) 替代 if-else 鏈,結構清晰protected virtual ReplyMessage ProcessXxxEvent(XxxEvent msg)DefaultProcess,返回「未處理」提示TextMessage、ImageMessage、ClickEvent 等繼承自 PostMessage/EventMessageProcessXxx 方法職責單一,易於編寫單元測試PostMessage 子類實例,無需模擬 XML 解析Dictionary<Type, Func<PostMessage, ReplyMessage>> 替換 switch,運行期動態註冊處理器| 指標 | 重構前 | 重構後 |
|---|---|---|
| 圈複雜度 | 極高(>50) | 低(每方法 <5) |
| 新增消息類型 | 修改核心函數 | 新增類 + 覆寫方法 |
| 單元測試 | 極難 | 易於隔離測試 |
| 代碼復用 | 0 | 高(繼承/組合) |
| 閱讀體驗 | 橫向滾動 | 清晰層級 |
重構的本質不是炫技,而是將隱性邏輯顯性化,將耦合依賴解耦化。下次遇到「箭頭代碼」,請記住:拆分、多態、模板方法,是你的三把利刃。