项目剖析

经过了前面三道由易到难的练习,相信大家已经渐渐习惯了重构的节奏,并且在实践中感受到了由细小的修改累积而成的改进系统设计的巨大力量。在这最后一道练习题中,我们来练练重构和面向对象。

在一些语言里(比如 Java)一切组成都是对象,而在其他一些语言里(比如 JavaScript,C/C++)对象则不是必须的语素。但是根据笔者几年来接触的系统来看,“面向对象”与否跟所用的语言本身并无必然的关联,我们很容易写出“过程式”的代码来操纵数据,这一点在强调“一切皆为对象”的 Java 上也颇为常见。而在一个中大型项目上这样做的结果——正如 Martin Fowler 在《企业应用架构模式》中所指出的——便是隔离了数据及其对应的操作,使系统的维护变得更加困难。

面向对象的设计技术便是这个问题的解决方案:将数据和数据对应的行为作为整体看待,形成“对象”的概念。有了对象,我们再也不用到处寻找数据上可能的操作,甚至很多时候不需要关注具体的数据结构,只需要查看对象上支持的操作,便足以完成任务。这是面向对象的“封装”为我们带来的优势:更好的隔离、更独立的模块、更内聚的上下文。

说到底,学习面向对象的过程,我们经常碰到的几个问题无非:什么数据和行为可以放在一起、如何设计对象之间的交互、类的边界在哪里……遗憾的是,这些问题并无一劳永逸的答案,很多时候需要开发者拥有诸多经验进行综合判断。除了阅读《实现模式》等深入讲解面向对象的书籍,“对象健身操”就给出了 9 条非常实用且可操作的建议:

  1. 方法只使用一级缩进(One level of indentation per method)

  2. 拒绝使用 else 关键字(Don’t use the ELSE keyword)

  3. 封装所有的原生类型和字符串(Wrap all primitives and Strings)

  4. 一行代码只有一个“.”运算符(One dot per line)

  5. 不要使用缩写(Don’t abbreviate)

  6. 保持实体对象简单清晰(Keep all entities small)

  7. 任何类中的实例变量都不要超过两个(No classes with more than two instance variables)

  8. 使用一流的集合(First class collections)

  9. 不使用任何 Getter/Setter/Property(No getters/setters/properties)

这里面既有非常明了、容易遵循的一些原则(比如不要使用缩写、拒绝使用 else 关键字、方法只使用一级缩进等),也有很具挑战、但往往价值也很大的原则,比如我个人觉得第 3、4、7、9 条原则就非常有益于我们设计出优秀的面向对象代码。当然,它有一定的挑战,你也会在这个练习中接受这些挑战。但是,你会发现这些挑战也不是那么难,而且它所带来的良好的面向对象设计,会使系统受益无穷。

有趣的是,在《重构 2》一书中虽然以非强制面向对象的 JavaScript 作为介绍性语言,作者同样花费了许多篇幅在介绍怎样重构到面向对象的代码,诸如“以对象取代基本类型”、“封装记录”、“封装数组”、“封装变量”、“函数组合成类”、“提炼类”/“内联类”、“以多态取代条件表达式”、“保持对象完整”等,几乎可说十分全面地覆盖了从各种情况重构到面向对象的手法。从这里也可以看出,面向对象实则是一种跨越了语言和范式的设计方法,值得好好理解和掌握。

那么,祝大家练功愉快。

Last updated