Clean Code 读书笔记九

要点汇总:

一般性问题

方法名称应该准确表达其具体行为

比如:

Date newDate = date.add(5)//加5天?5个月?

最好使用addDaysTo 或increaseByDays 明确方法的行为。

  • 使用多态 代替 switch或if else

    比如:

class RequestHandler {

    public void handleRequest(int action) {
        switch(action) {
            case LOGIN:
                doLogin();
                break;
            case LOGOUT:
                doLogout();
                break;
            case QUERY:
               doQuery();
               break;
        }
    }
}
interface Command {
    public void execute();
}

class LoginCommand implements Command {
    public void execute() {
        // do what doLogin() used to do
    }
}

class RequestHandler {
    private Map<Integer, Command> commandMap; // injected in, or obtained from a factory
    public void handleRequest(int action) {
        Command command = commandMap.get(action);
        command.execute();
    }
}
  • 用命名常量代替魔法数字

    不多说,代码中出现某个数字,如21,你知道什么意思么?

    这样 CommonConstants.AVERAGE_AGE=21,使用更好。

  • 不要再判断中写一堆&& ||的判断

    看看下边那个更易于理解

if (shouldBeDeleted(timer)) 

if (timer.hasExpired() && !timer.isRecurrent())
  • 避免否定性调节:

    肯定性条件比否定性条件更容易理解

    比如下边那一行更易理解呢?

if (buffer.shouldCompact())
if (!buffer.shouldNotCompact())
  • 方法只做一件事
public void pay() {
    for (Employee e: employees) {
        if (e.isPayday()) {
            Money pay = e.calculatePay();
            e.deliverPay(pay);
        }
    }
}

重构:

public void pay() {
    for (Employee e: employees)
    payIfNecessary(e);
}
private void payIfNecessary(Employee e) {
    if (e.isPayday()) calculateAndDeliverPay(e);
}
private void calculateAndDeliverPay(Employee e) {
    Money pay = e.calculatePay();
    e.deliverPay(pay);
}
  • 让时序耦合的代码更明显
 public class MoogDiver {
    Gradient gradient;
    List < Spline > splines;
    public void dive(String reason) {
        saturateGradient();
        reticulateSplines();
        diveForMoog(reason);
    }...
}

saturateGradient();reticulateSplines(); diveForMoog(reason);

三者的关系并没有很好的突出,更好的重构是:

public class MoogDiver {
    Gradient gradient;
    List < Spline > splines;
    public void dive(String reason) {
        Gradient gradient = saturateGradient();
        List < Spline > splines = reticulateSplines(gradient);
        diveForMoog(splines, reason);
    }...
}
  • 使用枚举代替常量

    不要在用

public static fianl int ....

使用enum代替

  • Don’t Inherit Constants
public class HourlyEmployee extends Employee {
    private int tenthsWorked;
    private double hourlyRate;

    public Money calculatePay() {

        int overTime = tenthsWorked - straightTime;
        return new Money(
        hourlyRate * (tenthsWorked + OVERTIME_RATE * overTime));
    }...
}

TENTHS_PER_WEEK 、OVERTIME_RATE这两个常量来自哪里?

public abstract class Employee implements PayrollConstants {
    public abstract boolean isPayday();
    public abstract Money calculatePay();
    public abstract void deliverPay(Money pay);
}
public interface PayrollConstants {
    public static final int TENTHS_PER_WEEK = 400;
    public static final double OVERTIME_RATE = 1.5;
}

这种通过继承或实现的方式获取常量,是对常量作用域的忽视,怪异的使用。应该用引入静态类的方式在代码中直接使用常量。

import static PayrollConstants.*;

名称与命名

使用描述性名称

名称很重要,一个准确的名称可以大幅度提高代码的可读性。

public int x() {
    int q = 0;
    int z = 0;
    for (int kk = 0; kk < 10; kk++) {
        if (l[z] == 10) {
            q += 10 + (l[z + 1] + l[z + 2]);
            z += 1;
        } else if (l[z] + l[z + 1] == 10) {
            q += 10 + l[z + 2];
            z += 2;
        } else {
            q += l[z] + l[z + 1];
            z += 2;
        }
    }
    return q;
}
public int score() {
    int score = 0;
    int frame = 0;
    for (int frameNumber = 0; frameNumber < 10; frameNumber++) {
        if (isStrike(frame)) {
            score += 10 + nextTwoBallsForStrike(frame);
            frame += 1;
        } else if (isSpare(frame)) {
            score += 10 + nextBallForSpare(frame);
            frame += 2;
        } else {
            score += twoBallsInFrame(frame);
            frame += 2;
        }
    }
    return score;
}

两段代码对比一下即可知道名称的重要。

  • 变量的作用范围越大,越应该重视名称的重要。
  • 不要用名称掩盖了内容。
public ObjectOutputStream getOos() throws IOException {
    if (m_oos == null) {
        m_oos = new ObjectOutputStream(m_socket.getOutputStream());
    }
    return m_oos;
}

更准确的名称应该是: createOrReturnOos

测试

  • 使用测试覆盖工具
  • 测试边境条件

    很多问题都出在边界上,如数组越界等等。注意边境!

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-11 05:34:08

Clean Code 读书笔记九的相关文章

Clean Code 读书笔记三

clean code 之方法(函数) - 短小 ,再短小,更短小 20行最佳 只做一件事 准确说来每个方法应该是只做抽象概念上的的一件事 只做一件事的方法是无法把逻辑分段的 自顶向下的代码 To say this differently, we want to be able to read the program as though it were a set of TO paragraphs, each of which is describing the current level of

clean code 读书笔记一

什么是 clean code ? 大神对优雅代码的定义: I like my code to be elegant and efficient. The logic should be straightforward to make it hard for bugs to hide, the dependencies minimal to ease maintenance, error handling complete according to an articulated strategy,

Clean Code 读书笔记五

Use Exception Rather than Return Code(使用异常而不是错误处理) public class DeviceController {... public void sendShutDown() { DeviceHandle handle = getHandle(DEV1); // Check the state of the device if (handle != DeviceHandle.INVALID) { // Save the device status

Clean code 读书笔记二

细节汇总: 拒绝在容器类型的命名中使用 该容器类型 List flaggedCells = new ArrayList(); As we'll see later on, even if the container is a List , it's probably better not to encode the container type into the name. -相同的意思,使用一致的拼写,并保证专词专意,一次一意 Spelling similar concepts similar

读书笔记(九)

HAL:硬件抽象层 HAL ( Hardware Abstraction Layer,硬件抽象腔,是建立在Linux驱动之上的一套翻字库.这套程序 j率并不属于 Linux 内核, 而是属于 Linux 内核层之上的应用层. 在传统的 Linux.系统中Linux驱动一般有两种类型的代码:访问硬件寄存器的代码和业务逻辑有 码.对于访问硬件寄存器的代码,并没有什么秘密可言,因为这都是调用的 Linux 内核的标准函数〈如 io位ad32)进行的标准操作 而Linux驱动的业务逻辑部分对击有些企业或

how tomcat works 读书笔记九 Session管理

在看本文之前,请先查阅相关Session与Cookie的资料. Catalina通过一个叫管理器的组件来完成 session 管理工作,该组件由org.apache.catalina.Manager interface 接口表示.一个管理器通常跟一个上下文容器相关联,它负责创建.更行以及销毁 session 对象并能给任何请求组件返回一个合法的 session. Session对象 uml图如下: 看上图,我们知道我们使用的session其实是javax.servlet.http.HttpSes

《Clean Code》读书笔记——第二周

本周我阅读了<Clean Code>. "神在细节中!",建筑家范德罗如是说.他当然专注于基于宏伟构架之上的永恒建筑形式,他也同样为自己设计的建筑挑选门把手.同样软件开发也是这样,小处见大.在宏伟的建筑作品中,我们也要关注细节的回响.重点便是整理,从而达成Clean.一个很好的例子是对于变量命名,认真对待每个变量名.书中作者说,我们就像一群代码猴子,无视混乱无序,失去代码的真谛.整洁的代码正是迈向编程之美的基础,重要性毋庸置疑. 作者断言,我们永远需要代码.我们可以创造各种

读书笔记:《梦断代码Dreaming in Code》

读书笔记:<梦断代码Dreaming in Code> 拿到<梦断代码>书后,一口气翻了一遍,然后又用了3天时间仔细读了一遍,也不禁掩卷长叹一声,做软件难.虽难,仍要继续走下去,可以把软件的范围限制得小一些,用敏捷方法等过程会使软件失败的风险小一些,毕竟我们还没有写书上所说的那样的大型软件. 第0章 软件时间 一开始看到第0章并没有感觉多么奇怪,可能程序员的思维方式已经固化在大脑中了,但读到作者关于第0章无意搞笑时,也不禁哑然失笑,为什么程序员要 从0开始计数?因为计算机从0开始计

《Linux内核设计与实现》读书笔记(十九)- 可移植性

摘自http://www.cnblogs.com/wang_yb/p/3512095.html <Linux内核设计与实现>读书笔记(十九)- 可移植性 linux内核的移植性非常好, 目前的内核也支持非常多的体系结构(有20多个). 但是刚开始时, linux也只支持 intel i386 架构, 从 v1.2版开始支持 Digital Alpha, Intel x86, MIPS和SPARC(虽然支持的还不是很完善). 从 v2.0版本开始加入了对 Motorala 68K和PowerPC