代码重构之 —— 一堆if、esle 逻辑的处理

这几天,接手一个同事的代码,关于微信接口开发的,那一堆的 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 内的语句块需要变动,因为要面对不同的用户,他们的处理都是不同的。

有不少朋友都误会了,以为我是为了消除 if,else,在这里,if、else
带来的问题只是阅读读上的不便,真正要害的的地方是if、else间的逻辑代码块,这些代码会因为不同的客户,做出不同的处理,每换一个客户,都泛及到修改里面的代码,所以很有必要对它进行重构。

为什么不用命令模式、或者把类型与处理方法保存在键值对。我们先来考虑一个问题,这些类型有没有增加的可能性?有,但是这个慨率比较小的,就算发生了,但是修改的正本也是非常低的,而且,当然你增加了一个后,以后需要增加一个的慨率更加小了。

总结一下这种处理的好处:对于开发人员来说,它非常便于阅读和理解,而对于使用者来说,通过重载来实现,也是很容易接受的。

代码重构之 —— 一堆if、esle 逻辑的处理

时间: 2024-10-05 15:15:13

代码重构之 —— 一堆if、esle 逻辑的处理的相关文章

Android 项目代码重构思想总结

代码重构的根本思想是模块化.灵活性.高内聚.低耦合. Android 项目代码重构: 将与业务逻辑无关的公共基本资源.工具类等等抽取到一个lib 工程中,主程序中只放与业务逻辑相关的代码和工具类: 1.将公共资源类进行抽取,包括: string.xml color.xml styel.xml drable  中自定义的shap .selector.anim 这些资源基本是和程序业务逻辑无关的,将其放到主工程中只会增加代码量影响对程序业务逻辑的理解. 工程项目所特有的资源可以采取继承于lib库工程

代码重构的必要性分析及实施建议

代码重构在软件开发过程中,是一项重要非紧急的工作.但大多数情况下,人们都会因为其非紧急,而忽略其重要性.等到代码重构演变成重要且紧急的工作时,一般就只有放弃了,因为由于长期的技术欠债,此时代码已经变得无法扩展,成为一堆僵死的代码. 代码重构的重要性 代码重构是为了使代码具有很好的可读性.可维护性.可扩展性.可重用性. 为什么要进行代码重构? 代码在演化过程中,会由于各种不同的原因,不断产生bad smell.如果不及时清理,bad smell会不断积累,代码逐渐腐化,最终导致代码不可用. 代码腐

step 1 代码重构

代码重构 代码重构介绍 重构目的 相同的代码最好只出现一次 主次方法 主方法 只包含实现完整逻辑的子方法 思维清楚,便于阅读 次方法 实现具体逻辑功能 测试通过后,后续几乎不用维护 重构的步骤 1  新建一个方法 ?                     新建方法 ?                     把要抽取的代码,直接复制到新方法中 ?                     根据需求调整参数 2  调整旧代码 ?                     注释原代码,给自己一个后悔的

代码重构实例之数据聚集

敏捷开发强调,要经常重构代码.在开发过程中,往往是开发和重构交替进行.短暂的重构,可以使得后续的开发维护更加容易.我觉得,代码重构可以分为逻辑重构和数据结构重构.数据结构的重构往往需要对代码进行多处改动:但是,数据结构的重构也可以为后续的开发维护带来更大的便利.这里就是一个数据结构重构的例子. 这是以前的一次代码重构经历,今天想起了,就记下来,帮助自己记忆.当然,既然是重构,总得承认自己写的第一版丑陋的代码. 为了方便描述,采用javascript来进行说明. 故事是这样的.刚开始,任务是画一些

从案例深入了解如何重构代码-重构计划

项目名称A,某公司重点项目,已经正式上线运行几年了,公司业务遍布全球,很多国家都有办事处或研发部门,也就需要使用该系统.并且随着公司的不断发展,业务流程也在不断地完善和变化. 技术上,项目是CS架构的,支持在线和离线两种操作方式,对于在线方式,数据访问是直连服务器上的Oracle数据库,离线的数据访问是连接本地的Access数据库;对于本地数据库,系统提供WebService来实现本地数据的同步. 目前项目代码的规模已经达到100多万行,负责项目开发和维护是由同一个团对来承担,其中的开发和设计人

编码规范和代码重构的一些建议

首先推荐两个工具,一个是Resharper 一个是dotcover 代码应在注释较少的前提下能让别人读的懂,而不是只能让机器读的懂 如果自己都觉得自己写的代码丑,那么请您重构 尽可能的避免重复代码 必要的时候可以使用静态变量来保存查询出来的数据,建议将静态变量设置为只读的并且私有的,通过只读属性来访问它 区别对待静态变量和静态属性 静态属性中直接调用方法,不会带来性能的提升,而静态变量可以 谨慎使用可读的.非私有的静态变量或属性 代码的暴露程度尽可能的低(能用internal不用protecte

我的代码重构经验

说明 本文在<MDU某产品OMCI模块代码质量现状分析>一文的基础上,分享作者对该模块进行重构时的实践经验. 具体的重构手段可参考<代码大全2>或<重构:改善既有代码的设计>,本文不再班门弄斧,而侧重重构时一些粗浅的“方法论”,旨在提高重构效率. 作者未采用重量级的重构工具,仅用到Source Insight的”Smart Rename”功能.也未使用CUnit等单元测试工具,而是通过在线调测和自动化测试保证代码的正确性. 一 背景 MDU系列产品从他处接手,OMCI模

记录一次代码重构的思路(初稿)

本次重构,需要注意: 1.代码的规范,详细的注释 主要集中 在方法和类的描叙 2.目录结构的合理,包名的设计 首先目录的设计: 1.activitiy的目录 (所有的界面) 2.serverice目录 (后台的服务) 3.通用的目录 (通用的方法与常量:譬如时间,字符串操作,定义常量) 4.数据库 目录 (sqlite的方法) 5.网络通信目录(上传数据与更新软件的) 6.文件目录(文件操作的目录) 7.参数配置目录 (配置xml的方法) 最终设计的结果: 文件目录与参赛配置,都放到tools中

代码重构(二):类重构规则(Swift版)

在上篇博客<代码重构(一):函数重构规则(Swift版)>中,详细的介绍了函数的重构规则,其中主要包括:Extract Method, Inline Method, Inline Temp, Replace Temp with Query, Introduce Explaining Variable, Split Temporary Variable, Remove Assignments to Parameters, Replace Method with Method Object等.关于