《重构》

任何一个傻瓜都能写出计算机可以理解的代码,唯有写出人类容易理解的代码,才是优秀的程序员。

1、重构的原则

1.1、为何重构

  • 重构改进软件设计。很多时候为了短期目的,在程序完成之后,会贸然修改代码。慢慢的程序就会失去原来的结构设计,会导致代码越来越难理解。因此重构就是在整理代码,让代码越来越整洁。
  • 重构使软件更容易理解。很多时候软件后续的开发者,不一定是原来的开发者。甚至很多时候,即使是自己开发的代码,过一段时间后,也会逐渐忘记当时的设计原则。
  • 重构帮助找bug。
  • 重构提高编程速度。

1.2、何时重构

重构不应该专门拨出时间来做,而是应该随时随地进行。

重构应遵循三次原则。同一件事,第一次做的时候,尽管去做;第二次做的时候,可能会反感,但还是会去做;第三次还做的时候,无论如何都不要在去做了,应该考虑重构。

  • 添加功能的时候。每当为软件添加新特性的时候,当发现旧的代码难以理解的时候,可以重构。
  • 修补错误的时候。调试的时候重构,多半是为了提高代码的可读性。
  • 复审代码的时候。自己的代码对自己来说,是清晰的。但开发者还要为那些不熟悉逻辑、功能的人着想。在极限编程中的结对编程中,将代码审核做到了极致。

2、代码的坏味道

2.1、重复代码

应尽量避免出现重复的代码。当发现重复代码的时候,应该使用抽象方法的策略,将这些代码提炼成一个新的函数。

2.2、过长的函数

短的函数更容易理解和复用。早期的语言,子程序调用需要额外的开销,但现代语言几乎已经不存在这个问题了。拆分函数的原则是,当你觉得需要写一段注释,来说明一些内容的时候。这段要说明的代码,就应该独立成一个函数。

2.3、过大的类

如果某个类代码过多的话,其实就是一般意义上的超级类超级类做的事情太多,内部往往有大量的实例变量。这些都是代码的坏味道,应将这个类进行拆分。一般的策略是先确定客户端是如何调用的,根据调用方式进行分解。另外像数据和行为,也应当进行分离。

2.4、过长的参数列

记得在《代码整洁之道》一书中提到,函数的参数没有最好,其次是一个、两个,最多不要超过三个。当出现三个以上的参数的时候,就需要反思,是不是可以使用对象进行封装。本书中也提到了这个理念。

2.5、发散式变化和散弹式修改

这两个观念类似,发散式变化指的是,某个类会由于一个原因出现多处修改。理论上一个类只因一种变化而需要修改。

散弹式修改指的是,一旦遇到某个变化,需要改多个类的多个方法。由于需要修改地方散布在多个对象的多个地方,因此需要整理这些代码。

2.6、依赖地狱

  • 面向对象的全部要点在于,将数据和对数据的操作行为,全部包装在一起。如果某个函数对其他类中的数据使用,超过了自己类。那说明这个函数放在这个类是不合适的。
  • 如果对象A请求对象B,然后在请求对象C…。这就是消息链,在代码中可能出现getThis().getThat().getXXX().getXXX()。这种设计的缺点是,结构过于紧密耦合,一旦某个对象发生变化,整个程序都需要调整。
  • 两个类彼此对对方的私有变量过于感兴趣。通常这种情况出现在子类对超类的了解,超过了超类的主观愿望。

2.7、switch

从本质上说,switch语句意味着重复。当出现switch语句的时候,考虑用多态来实现。

2.8、纯粹的数据类

Data Class,一般拥有一些字段,以及用于访问这些字段的函数,如get() set()。除此之外,这个类没有其他功能,这样的类一般称之为数据类。数据类通常是必须的,但数据类还应承担更多的责任,要充分的参与整个系统的工作。

2.9、过多的注释

注释本身是需要的,但过多的注释意味着糟糕的代码。应该利用重构的方法,尽可能的减少注释。代码已经说明一切

3、重构函数

3.1、提炼函数

遇到过长的函数或难以理解的代码,最好用简短而命名良好的短函数取代。函数的命名应该是做什么而非怎么做。尤其是遇到代码的业务层级不一致的时候,更应该将级别低的代码提炼进一个独立的函数,并将函数名称解释该函数的用途。

// 重构前代码
 void printOwing(double amout)
{
    printBanner();
    System.out.println(_name);
    System.out.println(_amout);
}

// 重构后代码
void printOwing(double amout)
{
    printBanner();
    printDetails(amout);
}

void printDetails(double amout)
{
    System.out.println(_name);
    System.out.println(_amout);
}

3.2、以查询函数代替临时变量

如果程序中有临时变量,保存一系列的运算结果。应该将这个运算结果提炼出来,以查询函数的方式,在其他地方进行调用。

// 重构前代码
double basePrice = _quan * _itemPrice;
if (basePrice > 1000){
    return basePrice * 0.95;
} esle {
    return basePrice * 0.8;
}

// 重构后代码
if (getBasePrice() > 1000){
    return getBasePrice() * 0.95;
} esle {
    return getBasePrice() * 0.8;
}

double getBasePrice()
{
    return _quan * _itemPrice;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值