【读书笔记】代码整洁之道

第三章 函数

  • 短小
  • 只做一件事
  • 每个函数一个抽象层级
  • switch语句
    • switch语句容易过长,特别是当逻辑都写在switch所在的类中时,容易:
      • 违反单一权责原则(SRP)
      • 违反开放闭合原则(OCP)
    • 解决方案:
      • 将switch语句埋到抽象工厂下
      • 使用switch语句为排程逻辑创建新的实体(不是switch接受参数然后直接执行,而是返回new的子类对象)
      • 即只出现一次,用于创建多态对象,而且隐藏在继承关系中。
  • 函数参数
    • 尽量避免函数参数大于三个
    • 标识参数
      • 向函数传入布尔值简直就是骇人听闻的做法。这样做,方法签名立刻变得复杂起来,大声宣布本函数不止做一件事。
    • 参数对象
      • 如果函数看起来需要2、3个或3个以上的参数,就说明其中一些参数应该封装为类了。
  • 分隔指令与询问(分离读和写。eg. 先通过读判断是否需要写,然后写函数,不要写到一个函数里,或明确函数名字)
  • 使用异常代替返回错误码(错误处理代码可以从主路径代码中分离)
    • 抽离Try/Catch代码块,另外形成函数
    • 错误处理就是一件事。函数应该只做一件事,因此处理错误的函数不该做其他事,try应该是该函数第一个单词,catch/finally后也不该有其他内容。

第四章 注释

  • 注释的恰当用法是弥补我们在用代码表达意图时遭遇的失败。最好不是用注释而是用代码来表达。

第六章 对象和数据结构

得墨忒定律(The Law of Demeter)认为,模块不应了解它所操作对象的内部情形。

  • 隐藏结构:把逻辑交给对象去做,而不是从对象中获取内部结构,然后自己做。

数据传输对象(DTO):只有公共变量、没有函数的类。

第七章 错误处理

使用不可控异常:

  • 可控异常的代价是违反开放/闭合原则,如果你在方法中抛出可控异常,而catch语句在三个层级之上,你就得在catch语句和抛出异常处之间的每个方法签名中声明该异常。

定义常规流程:

  • 特例模式(Special Case Pattern)。创建一个类或配置一个对象用来处理特例。你来处理特例,客户代码就不用处理异常行为了。异常行为被封装到特例对象中。

eg. 特例是调用函数在内部遇到特殊情况时,返回一个继承/继承同一接口的另一种多态对象,特殊情况在该类对象中处理,而不是在外部处理。

别返回null值。可以抛出异常或返回特例对象。如果是返回集合类型,可以考虑返回空集合。

第九章 单元测试

整洁的测试:

  • 呈现了 构造-操作-检验(Build-Operate-Check)

每个测试一个概念

  • 每个测试函数只测试一个概念

F.I.R.S.T. 快速的测试应遵循

  • 快速
  • 独立
  • 可重复:在任何环境中重复通过
  • 自足验证:应该有布尔值输出而非查看日志来判断是否通过
  • 及时(Timely):测试应该及时编写。单元测试应该恰好在使其通过的生产代码之前编写。如果在编写生产代码之后编写测试,你会发现生产代码难以测试。

第十章 类

类应该短小

  • 类的名称应当描述其权责。类名越含混,该类越有可能拥有过多的权责。例如,如果类名中包含
  • 单一权责原则(SRP):类或模块应有且只有一条加以修改的理由
  • 内聚:类应该只有少量实体变量,类中的每个方法都应该操作一个或多个这种变量。通常而言,方法操作的变量越多,就越黏聚到类上。如果一个类中的每个变量都被每个方法所使用,则该类具有最大的内聚性。
    • 一般来说,创建这种极大化内聚类是既不可取也不可能的;另一方面我们希望内聚性保持在较高的位置。内聚性高,意味着类中的方法和变量相互依赖、互相结合成一个逻辑整体。
    • 保持函数和参数列表短小的策略,有时会导致一组子集方法所使用的实体变量数量增加。出现这种情况时往往意味着至少有一个类要从大类中挣扎出来。你应当尝试将这些变量和方法拆分到两个或多个类中,让新的类更为内聚。
  • 保持内聚性就会得到许多短小的类
    1. 将一个有许多变量的大函数拆为单独的小函数,是否要将许多变量作为参数传到新函数?
    2. 没必要,将这些变量提升为类的实体变量。但是类丧失了内聚性,只为允许少量函数共享而存在的实体变量越来越多。
    3. 这些函数想要共享变量,为什么不让他们有自己的类呢?——将大函数拆为小函数,往往也是将类拆分为小类的时机。

为了修改而组织

  • 隔离修改:利用多态,将新的逻辑写进新的多态类中,调用该逻辑的函数参数类则是抽象类(或接口)。通过降低链接度,我们的类还遵循了另一条类设计原则,依赖倒置原则(Dependency Inversion Principle,DIP),DIP认为来应当依赖于抽象而不是依赖于具体细节。

第十一章 系统

如何在更高的抽象层级——系统层级——上保持整洁

将系统的构造与使用分开

  • 构造与使用是非常不一样的过程。(类比一下建筑的建设和使用)
  • 软件系统在启始的过程中构建应用对象,也会存在相互缠结的依赖关系。
    • eg. 延迟初始化:测试是个问题、而且违反单一权责原则
  • 分解main
    • 将全部构造过程搬迁到main或被称之为main的模块中,设计系统其余部分时,假设所有对象都已经正确构造和设置
  • 工厂
    • 让应用自行控制何时创建,但不感知构造细节
  • 依赖注入(Dependency Injection,DI),控制反转(Inversion of Control,IoC)在依赖管理中的一种手段.
    • 控制反转将第二权责从对象中拿出来,转移到另一个专注于此的对象中,从而遵循了单一权责原则

扩容

  • 横贯式关注面:面向切面编程(aspect-oriented programming,AOP)

Java代理

纯Java AOP框架

AspectJ的方面

测试驱动系统架构

  • 最佳的系统架构由模块化的关注面领域组成,每个关注面均用纯Java(或其他语言)对象实现。不同的领域之间用最不具有侵害性的方面或类方面工具整合起来。这种架构能测试驱动,就像代码一样。

明智使用添加了可论证价值的标准

系统需要领域特定语言(Domain-Specific Language,DSL)

第十二章 迭进

通过迭进设计达到整洁目的:Kent Beck关于“简单设计”的四条规则

  1. 运行所有测试
  2. 不可重复
  3. 表达了程序员的意图
  4. 尽可能减少类和方法的数量

简单设计规则1:运行所有测试

  • 只要系统可测试,就会导向保持类短小且目的单一的设计方案。遵循SRP的类,测试起来较为简单。测试编写得越多,就越能持续走向编写较易测试的代码。
  • 紧耦合的代码难以编写测试。编写测试越多,就越会遵循DIP之类的规则,使用依赖注入、接口和抽象等工具尽可能减少耦合。

简单设计规则2~4:重构

  • 有了测试,就能保持代码和类的整洁,方式就是递增式地重构代码。
  • 添加了几行代码后,就要琢磨一下变化。设计退步了吗?如果是就要清理,并运行测试,保证没有破坏任何东西。测试消除了对清理代码就会破坏代码的恐惧。

不可重复

  • “小规模复用”可大量降低系统复杂性
  • 模板方法模式

表达力

  • 好名称。类名、函数名
  • 保持函数和类尺寸短小
  • 采用标准命名法
  • 编写良好的单元测试
  • 不断尝试重构

尽可能少的类和方法

  • 不要过渡使用消除重复、代码表达力和SRP等基础概念
  • 本条优先级较低

第十三章 并发编程

“对象是过程的抽象,线程是调度的抽象。”——James O Coplien

为什么要并发

  • 并发是一种解耦策略。它帮助我们把做什么(目的)和何时(时机)做分解开。
    • 例如,Web应用的Servlet标准模式
  • 并发常常需要对设计策略的根本性修改

并发防御原则

  • 单一权责原则
    • 分离并发相关代码与其他代码
  • 推论:限制数据作用域
    • 谨记数据封装;严格限制对可能被共享的数据的访问
  • 推论:使用数据复本
  • 推论:线程应尽可能地独立
    • eg. HttpServlet

了解Java库

了解执行模型

  • 生产者-消费者模型
  • 读者-作者模型
  • 宴席哲学家

警惕同步方法之间的依赖

  • 避免使用一个共享对象的多个方法
    • 基于客户端的锁定——客户端在调用方法前锁定服务端
    • 基于服务端的锁定——在服务端内创建锁定服务端的方法,给客户端调用
    • 适配服务端——创建执行锁定的中间层

保持同步区域微小

很难编写正确的关闭代码

  • 尽早考虑关闭问题,尽早令其工作正常。

测试线程代码:不同编程配置、系统配置、负载条件下频繁运行。

  • 将伪失败看作可能的线程问题:不要将系统错误归咎于偶发事件
  • 先使非线程代码可工作
  • 编写可插拔的线程代码
  • 编写可调整的线程代码
  • 运行多于处理器数量的线程
  • 在不同平台运行
  • 调整代码并强迫错误发生
    • 装置试错代码
      • 硬编码:手工插入wait()``sleep()``yield()``priority()的调用
      • 自动化:使用异动策略搜出错误

第十四章 逐步改进

——对一个命令行参数解析程序的案例研究

只是大致看了一下,在书上看代码全是黑的,不一目了然,太费劲了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值