12.2 通过汇点来判断设计的好坏
上一节我们讨论了汇点在测试中扮演的重要角色,但除了用在测试中之外汇点还有其他的用处。其在影响结构图中的位置其实暗示了你如何才能让代码变得更好。
那么,到底什么是汇点呢?一个汇点其实就相当于一个自然封装边界。发现一个汇点就相当于发现了一个“漏斗口”,一大块代码的影响都得从这个口经过。就拿我们这个例子来说,如果BillingStatement.makeStatement方法是一堆发货单和货物的汇点的话,我们就知道当账单上列出的内容跟预期不符的时候该到哪去找原因了:问题只可能出在BillingStatement类本身或发货单和货物身上。同样,我们无需知道发货单和货物就可以调用makeStatement。以上这两点就基本体现了封装的精神:无需关心内部,而真的需要关心内部时,无需通过查看外部信息来理解它。我在寻找汇点的时候常常注意到,可以通过在类之间转移职责来达到更佳的封装性。
借助影响结构图来发现潜在的类
假设你手头有一个庞大的类,那么就可以借助于影响结构图来发现如何将这个类分解成较小的类。下面是一个Java中的例子。这个名为Parser的Java类有一个叫做parseExpression的公共方法。
public class Parser
{
private Node root;
private int currentPosition;
private String stringToParse;
public void parseExpression(String expression) { .. }
private Token getToken() { .. }
private boolean hasMoreTokens() { .. }
}
倘若我们为这个类描绘一幅影响结构图的话,就会发现parseExpression依赖于getToken和hasMoreTokens,但并不直接依赖于stringToParse或currentPosition(而getToken和hasMoreTokens则是直接依赖于它俩的)。这儿我们看到了一个自然封装边界,尽管这个边界并不十分狭窄(两个方法隐藏了两块信息)。我们可以把上面提到的这些方法和成员变量提取到一个名为Tokenizer的新类中,从而简化Parser类。
当然,要分离类里面的职责并非只有这一个办法。有时候我们也可以从名字当中获得一些线索,比如刚才这个例子中我们就看到有两个方法的名字中都具有“Token”这个单词。这可以帮助你用另一种眼光来审视一个庞大的类,后者可能进而会启发你完成一些漂亮的提取。
作一个练习,请为一个庞大的类之中的修改勾勒一幅影响结构图,并故意不去管那些椭圆节点的名字,而只是关注它们是怎样联系和聚集在一起的。在这样一种审视方式之下,看看图中的自然封装边界,把目光定位到这个边界内部的椭圆节点上,考虑给这组方法/变量起个什么样的名字,而这个名字就会成为你即将分离出来的新类的名字了。此外考虑是否需要适当修改某个方法/变量的名字。
上面这个练习最好跟你的队友们一起完成。你们就命名问题进行探讨带来的好处不仅止于目前正在做的工作。它们能够帮助你和你的团队形成一个关于“该系统是什么”以及“它能够成为什么”的共识。
要在程序的某部分完成一些侵入性的改动,理想的切入点便是在汇点编写测试。花点工夫将一组类从系统中划分出来,对它们做一点修改,以便可以在测试用具中实例化它们。之后,在你完成了特征测试的编写之后,便可以肆无忌惮地进行修改了。这时你已经在应用程序中制造出了一个“小绿洲”,在这块弹丸之地上你的工作变得相对容易不少。但是,请当心,这片“绿洲”有可能只是一个虚幻的海市蜃楼!







