入职新公司,接手已有的项目,重构技能是必须掌握的,这次从基础盘点下常用的重构方法,不深入设计模式。
什么是重构?
在不改变软件逻辑前提下,重新设计并组织代码的行为。
为什么重构?
接手旧项目的时候,以下场景一定不会陌生:
上司交过来的任务,,
拒绝是不可能的嘛....
实际上,远没有答应时的轻松:
代码看了半天还是看不懂啊,一个方法上千行,心累ing
若干天后,终于看懂代码了,但是发现IDE一堆警告,一看提示说存在重复的代码,整个项目都是警告,那么多重复代码,不会封装一下吗!
试着优化下代码,改着改着发现好多if-else,还是多层嵌套,每个嵌套的判断还很复杂,想想还是先不改了,万一改出问题,岂不是更糟糕!
脑壳痛...
没办法,只好拿出重构大法,见招拆招!
第一招:重复代码的提炼
重复代码是重构收效最大的手法之一。
好处:总代码量大大减少,维护方便,代码条理更加清晰易读。
重点就在于寻找代码当中完成某项子功能的重复代码,将它移动到合适的方法当中,并存放在合适的类当中。
使用泛型提取重复逻辑
第二招:冗长方法的分割
往往在我们提炼重复代码的过程中,就不知不觉的完成了对某一个超长方法的分割。
这其中有一点是值得注意的,由于我们在分割一个大方法时,大部分都是针对其中的一些子功能分割,因此我们需要给每一个子功能起一个恰到好处的方法名,方法名要说明此方法的用途,名称无法说明清楚时,才使用注释,这很重要。
class GoodExample
{
public void Method()
{
function1();
function2();
function3();
}
private void Function1()
{//function[1]
}
private void Function2()
{ //function[2]
}
private void Function3()
{ //function[3]
}
}
冗长的函数被分割,重复的逻辑被提取。也就是说函数(接口、类)要职责分明,也就是
单一原则
当方法较多且具有固定流程时,也就是设计模式中的模板方法
第三招:嵌套条件分支的优化
大量的嵌套条件分支是很容易让人望而却步的代码,应该极力避免这种代码的出现。
(1)将不满足某些条件的情况放在方法前面,并及时跳出方法,以免对后面的判断造成影响。
public void Method(Object A, Object B)
{
if (A != null)
{
if (B != null)
{ //code[1]
}
else
{ //code[3]
}
}
else
{ //code[2]
}
}
改成这样,好懂多了:
public void Method(Object A, Object B)
{
if (A == null)
{ //code[2]
return;
}
if (B == null)
{//code[3]
return;
}
//code[1]
}
(2)合并分支条件。
if (A != null)
{
if (B != null)
{ //code
}
}
改成:
if (A != null && B != null)
{//code
}
(3)大量分支
当含有大量分支(条件、状态)判断的时候,可以考虑设计模式中的状态模式
第四招:去掉一次性的临时变量
class BadExample
{
private int increment;
public void Method(int[] arr)
{
int n= arr.Length;
int temp = GetIncrement();
for (int i = 0; i < n; i++)
{
temp *= i;
}
}
}
class GoodExample
{
private int increment;
public void Method(int[] arr)
{
for (int i = 0; i < arr.Length; i++)
{
GetIncrement() *= i;//emm,简洁明了!
}
}
}
第五招:消除过长参数列表
将这些参数封装成一个对象传递给方法
class BadExample
{
public void Method(int i, int j, int k, int l, int m, int n)
{
//code
}
}
改成:
class Data
{
private int i;
private int j;
private int k;
private int l;
private int m;
private int n;
}
class GoodExample
{
public void Method(Data data)
{
//code
}
}
第六招:提取类或继承体系中的常量
一些字符串常量等,会让人对程序的意图产生迷惑。
字符串等类型的常量的消除,方便维护。因为我们只需要修改一个常量,就可以完成对程序中所有使用该常量的代码的修改。
可以使用静态类、结构、字段、枚举...
第七招:优化冗长的类
(1)拆分逻辑可分离的部分
这一步和方法一样,体现了单一原则和高内聚。
(2)让类提供该提供的方法
public class Data
{
public void DataMethod()
{
//do something
}
public int One{get;}
public int Two{get;}
public int Three{get;}
}
上层可能是这样调用的:
class Program
{
static void Main(string[] args)
{
GetThree(data);
}
public int GetThree(Data data)
{
return data.One * data.One * data.One;
}
}
我们在上层定义一个方法操纵一个类内部的成员;
这是不应该的,应在类的内部就提供这个方法:
public class Data
{
public void DataMethod()
{
//do something
}
public int GetThree(Data data)
{
return data.One * data.One * data.One;
}
public int One{get;}
public int Two{get;}
public int Three{get;}
}
这样在上层只需要调用这个方法即可。
(3)提取重复的成员到父类
这一步是自底向上的设计,当两个类出现相同的成员时,可以抽象出父类或接口,方便以后的扩展。
其他
1、纠正随意命名
无规律的命名让读代码的人头大,,,
2、删除无效注释
精简代码,简短,漂亮
3、约定:
if语句中的条件表达式的逻辑运算不要超过3个
团队合作中,书写约定非常重要,可以大大提升团队开发效率!
通过重构,我们要达到这样的目标:
总结
正在写的项目:重构应该随时进行
重构通常不是一次性的,它贯穿软件的整个生命周期,只要觉得不合理都是重构的时机
象、继承
旧的项目:先梳理既有业务的流程和详细规则,接着梳理技术架构,然后评估方案,就可以重构了~
重构
让代码更容易理解
改善内部结构,修改更容易
提高编程速度,加快业务迭代
经过重构之后:
(网图侵删)
是不是很形象?