2

tags: 重构,优雅代码,读书笔记

在《重构》一书中,列举了一些代码的坏味道,同时以举例方式讲解了重构代码的一些手法,本文是读书后的关于如何写好代码的笔记,主要包括可读性、代码职责、面向对象思维方面。

可读性

下面是一些提升代码可读性的手段、方法。

Extract Method

当一个方法比较复杂、行数较多时,读起来令人费解,这时应该抽取出一个个小段代码的方法,且合理的命名方法,主方法中调用这些方法完成它所做的事情。
当然也不只是方法复杂时需要抽取方法。

优势:
1、通过方法命名,让主方法调用这些方法就能清晰表达主方法的流程,不需要通过注释来解释代码作用
2、方法小了,代码简洁清晰,易于复用

引入解释性变量

代码逻辑繁杂时,或一些复杂运算,可以引入变量,并通过对变量的命名来提升可读性。
如:

    methodB(ClassX.methodC(methodA(a,  b)))
可以改为:
    int someValue = ClassX.methodC(methodA(a,  b));
    methodB(someValue);

不要对方法参数重新赋值

void method(Object A){
    A = new Object();
}

引入参数对象

当方法参列表较长时,提取对象进行包装。一般建议参数个数≤3。

Rename Method/Class

根据代码的功能职责合理命名,便于理解

用对象取代直接使用数组

用常量取代特殊意义的数字

其目的引入解释性变量类似

分解复杂条件表达式

将复杂的表达式拆分成多个简短的表达式,每一个明确其意义。
如:

if(a.status != null && a.status = true && date > XXX && date < YYY){
    ......
}
取代为:
if(validStatus(a.status) && valiadDate(date) ){
    ......
}

可以更清楚的表达出条件判断的含义

以特殊检查取代嵌套的if else

if与else本身表达的是平级的关系,如果是某些特殊罕见条件特殊处理,采用if return的形式予以重视。
这样能够清晰的体现代码的主流程,不被一些特殊的处理掩盖,读起来更顺畅。
如:

boolean flag;
if(conditionX){
    flag = false;
} else{
    if(conditionY){
        flag = false;
    } else{
        do something……
        flag = calculate();
    }
}
return flag;

改为:

if(conditionX) return false;
if(conditionY) return false;

do something……
flag = calculate();
return flag;

以异常取代错误码

服务内部不要采用错误码来表示错误,如return -1表示失败,而应该抛出异常表达
后端与前端服务间的交互可采用errorCode的方式。
关于异常可参考本人另一篇文章: https://my.oschina.net/hebaod...

代码职责

我们经常说面向对象的单一职责原则,大到一个系统、模块的职责边界划分,小到一个类、一个方法的职责。
清晰的划分类、方法的职责,保持其单一、稳定的功能,能避免日后代码越来越臃肿。

下面是关于代码职责的处理方法。

Move Method/Field

某个方法不应该属于这个类或package,移动方法到合适的地方。
某个属于不应该属于该对象,移动之。

Extract Class

类越来越大,如某个Service的public方法越来越多,功能混杂,考虑抽取不同的class维护这些方法或属性。

面向对象的思维

用多态取代条件表达式

代码中出现多个if或switch case语句根据不同的条件,采取不同的行为时,应该采用多态的思想。
如:

switch(var){
    case v1:
        behavior1();
        break;
    case v2:
        behavior2();
        break;
    defalut:
        behavior3();
}
可以提炼一个interfa Behavior,根据不同var创建不同的实现类,最后只需要调用behavior.method即可,也是一种策略模式的体现。

但是,上述说法还没彻底解决switch case的问题,因为要创建不同实现类,一种方法是定义一个map存储映射关系。

Method/Field 上移到超类/下移到子类

采用继承时,需要区分出某些属性,方法到底是共性还是特性,共性就应该上移到超类中。特性即仅某些子类才具有,应该下移到子类。合理的进行抽象。

提炼超类/接口/子类

发现代码中有一些共同或类似的行为属性时,要考虑提炼超类or接口。定义好抽象的关系,使代码保持内聚。
关于抽象类与接口参考:https://www.zhihu.com/questio...

组合与继承的选择

一般来说组合优先于继承,组合表达的是has a的关系,继承表达的是is a的关系。
组合的扩展性更强,且java不支持多继承。更多关于组合与继承的讨论自行Google吧。

ps:个人blog地址:https://my.oschina.net/hebaod...


hebaodan
108 声望7 粉丝

个人blog:[链接]