这本书非常薄, 里面的作者却不少, 来自thoughtworks的各个层面, 其中心就是围绕敏捷这个东西在说事儿, 没有必要从头看到尾, 各取所需吧. 比如对我来说, 只有"对象健身操"这一章勉强是看完了的.
优秀设计背后的核心理念其实并不高深. 比如内聚性, 松耦合, 零重复, 封装, 可测试性, 可读性以及单一职责. 这七条差不多是放之四海而皆准的准则了.
理解了封装就是隐藏"数据, 实现细节, 类型, 设计或者构造", 这只是设计出良好封装的代码的{dy}步而已.
最"极端", 最"变态"的准则:
- 方法只使用一级缩进
- 拒绝使用else关键字
- 封装所有的原生类型和字符串
- 一行代码只有一个"."运算符
- 不要使用缩写
- 保持实体对象简单清晰
- 任何类中的实体变量都不要超过两个.
- 使用{yl}的集合
- 不使用任何的getter/setter/property
庞大的方法通常缺少内聚性, 一个常见的原则就是将方法的行数控制在5行之类.
对于简单的条件判断, 我们可以使用卫语句和提前返回替换它.
如果代码的每一行都有多个".", 那么这个行为就可能是发生错误的位置了, 也许你的对象需要同时与另外两个对象打交道. 而且这些过量的"."说明你破坏了封装性. 尝试让对象为你做一些事情, 而不要窥视对象内部的细节. 封装的主要含义就是, 不要让类的边界跨入到它不应该知道的类型中.
比如一个采用多点的类:
public class Board { class Price { String representation; } class Location { Price current; } String boardRepresentation() { StringBuffer sb = new StringBuffer(); for (Location l : sequares()) { sb.append(l.current.representation.substring(0, 1)); } return sb.toString(); } private Location[] sequares() { return null; } }
重构之后:
public class RefactorBoard { class Price { String representation; String character() { return representation.substring(0, 1); } void addTo(StringBuffer sb) { sb.append(character()); } } class Location { Price current; void addTo(StringBuffer sb) { current.addTo(sb); } } String boardRepresentation() { StringBuffer sb = new StringBuffer(); for (Location l : sequares()) { l.addTo(sb); } return sb.toString(); } private Location[] sequares() { return null; } }
我们总会不知觉的在类名, 方法名或者变量名中使用缩写. 请xx这个诱惑. 缩写会令人困惑, 也容易隐藏一些更严重的问题.
想想你为什么要使用缩写, 因为你厌倦了一遍又一遍的敲打单词, 如果是这种情况, 也许你的方法调用过于频繁, 你是不是应该停下来xx一下重复了? 因为方法的名字太长? 这可能意味着有些职责没有放在正确的位置或者有缺失的类.
尽量保持类名和方法名中只包含一到两个单词, 避免在名字中重复上下文信息. 比如某个类是Order, 那么方法名就不必叫做shipOrder()了, 把它简化成ship().
每个类的长度都不能超过50行, 每个包中包含的文件不超过10个.
代码超过50行的类所做的事情通常都不止一件, 这回导致他们难以被理解和重用. 小于50行的代码的类还有一个妙处: 它可以在一屏显示, 不需要滚屏, 这样程序员可以很容易, 很快速地熟悉这个类.
创建这样的小类会有什么挑战呢? 通常会有很多成组的行为, 它们逻辑上是应该在一起的, 这时就需要使用包机制来平衡, 随着类变得越来越小, 职责越来越少, 加之包的大小也受到限制, 你就会逐渐注意到, 包中的类越来越集中, 他们就能够协作完成一个相同的目标. 包和类一样, 也应该是类聚的, 有一个明确的意图. 保证这些包足够小, 就能使它们有一个真正的标识.
大多数的类应该只负责处理单一的状态变量, 有时候也可以拥有两个状态变量, 每当为类添加一个实例变量, 就会立即降低类的内聚性. 一般而言, 编程如果遵守这些规则, 你就会发现只有两种类, 一种只负责维护一个实例变量的状态; 另一种类只负责协调两个独立的变量. 不要让这两种职责同时出现在一个类中.
将一个对象从拥有大量属性的状态, 结构成分层次的, 相互依赖的多个对象, 会直接产生一个更实用的对象模型.