牵一毛而需要动全身的修改
当你发现修改一个小功能,或增加一个小功能时,就引发一次代码地震,也许是你的设计抽象度不够理想,功能代码太过分散所引起的。
类之间需要过多的通讯
A类需要调用B类的过多方法访问B的内部数据,在关系上这两个类显得有点狎昵,可能这两个类本应该在一起,而不应该分家。
过度耦合的信息链
"计算机是这样一门科学,它相信可以通过添加一个中间层解决任何问题",所以往往中间层会被过多地追加到程序中。如果你在代码中看到需要获取一个信息,需要一个类的方法调用另一个类的方法,层层挂接,就象输油管一样节节相连。这往往是因为衔接层太多造成的,需要查看就否有可移除的中间层,或是否可以提供更直接的调用方法。
各立山头干革命
如果你发现有两个类或两个方法虽然命名不同但却拥有相似或相同的功能,你会发现往往是因为开发团队成员协调不够造成的。笔者曾经写了一个颇好用的字符串处理类,但因为没有及时通告团队其他人员,后来发现项目中居然有三个字符串处理类。革命资源是珍贵的,我们不应各立山头干革命。
不完美的设计
在笔者刚完成的一个比对报警项目中,曾安排阿朱开发报警模块,即通过Socket向指定的短信平台、语音平台及客户端报 警器插件发送报警报文信息,阿朱出色地完成了这项任务。后来用户又提出了实时比对的需求,即要求第三方系统以报文形式向比对报警系统发送请求,比对报警系 统接收并响应这个请求。这又需要用到Socket报文通讯,由于原来的设计没有将报文通讯模块独立出来,所以无法复用阿朱开发的代码。后来我及时调整了这个设计,新增了一个报文收发模块,使系统所有的对外通讯都复用这个模块,系统的整体设计也显得更加合理。
每个系统都或多或少存在不完美的设计,刚开始可能注意不到,到后来才会慢慢凸显出来,此时唯有勇于更改才是最好的出路。
缺少必要的注释
虽然许多软件工程的 书籍常提醒程序员需要防止过多注释,但这个担心好象并没有什么必要。往往程序员更感兴趣的是功能实现而非代码注释,因为前者更能带来成就感,所以代码注释 往往不是过多而是过少,过于简单。人的记忆曲线下降的坡度是陡得吓人的,当过了一段时间后再回头补注释时,很容易发生"提笔忘字,愈言且止"的情形。
曾在网上看到过微软的代码注释,其详尽程度让人叹为观止,也从中体悟到了微软成功的一个经验。
如何使用重构
VS.NET 2005中包括一个菜单"重构",你可以用它来实现一些常见的重构任务。下图显示出这个重构菜单和它的菜单项。重构菜单
VS.NET 2005进行重构的方法有以下几个:
• 重构类型
<1>. 提取方法
<2>. 重命名
<3>. 封装字段
<4>. 提取接口
<5>. 将局部变量提升为参数
<6>. 移除参数
<7>. 重新排列参数
【1】• 提取方法
<1>. 可以通过从现有成员的代码块中提取选定的代码来创建新方法.
<2>. 创建的新方法中包含选定的代码,而现有成员中的选定代码被替换为对新方法的调用.
<3>. 代码段转换为其自己的方法,使您可以快速而准确地重新组织代码,以获得更好的重用和可靠性.
• 优点
<1>. 通过强调离散的可重用方法鼓励最佳的编码做法。
<2>. 鼓励通过较好的组织获得自记录代码。当使用描述性名称时,高级别方法可以像读取一系列注释一样进行读取。
<3>. 鼓励创建细化方法,以简化重载。
<4>. 减少代码重复.
• 实例
当你编写了一个代码很长的方法,它包含一些非常复杂的算法集合。在完成该方法以后,你可能意识到它变得太大和太复杂了,以至于其它小组成员无法容易地理解它。因此,你决定把它拆分成多个小函数。这不仅会简化你的代码而且还能够改进其易读和可维护性。"重构"菜单下的 "提取方法"选项正是适合这一工作。
假设方法为
(1) 用选中 string s = ""; 然后点击"提取方法"菜单选项。立即出现"提取方法"对话框。
(2) 按“确定”,结果如下:
重构为我们完成了两件事情:
· 它根据你的每一次选择创建一个新的方法并且替换其中的所有选择的代码。
· 它用一个到这个新创建方法的调用来替换选择的行。
【2】• 重命名
<1>. 提供了一种重命名代码符号(如字段、局部变量、方法、命名空间、属性和类型)标识符的简单方法.
<2>. “重命名”功能除了可用来更改标识符的声明和调用以外,还可用来更改注释中和字符串中的名称.
• 在何处可以使用重命名操作?
<1>. 代码编辑器
<2>. 类视图
<3>. 对象浏览器
<4>. Windows 窗体设计器的“属性网格”
<5>. 解决方案资源管理器
• 重命名执行些什么操作?
<1>. 字段
• 将字段的声明和用法更改为新名称。
<2>. 局部变量
• 将变量的声明和用法更改为新名称。
<3>. 方法
• 将方法的名称以及对该方法的所有引用更改为新名称。
<4>. 命名空间
• 将声明、所有正在使用的语句及完全限定名称中的命名空间名称更改为新名称。
<5>. 属性
• 将属性的声明和用法更改为新名称。
<6>. 类型
• 将类型的所有声明和所有用法都更改为新名称,包括构造函数和析构函数。对于部分类型,重命名操作将传播到其所有部分。
• 实例
假设我们需要“NewMethod”重命名为“NewMethod2”。
选中 “NewMethod” 然后点击"重命名"菜单选项。立即出现"重命名"对话框。
结果:
【3】• 封装字段
<1>. 可以从现有字段快速创建属性,然后使用对新属性的引用无缝更新代码.
<2>. 当某个字段为public(C# 参考)时,其他对象可以直接访问该字段并对其进行修改,而不会被拥有该字段的对象检测到。通过使用属性(C# 编程指南)封