这一章提到新手做设计时的常见错误。
我最喜欢这一章,以前看的时候,为了追求所谓的速度,把书中的实例统统略过,真有点买椟还珠的味道。另外说明一下,读书笔记为什么突然跳到第11章。
最简单的原因是因为我对这一章有感觉,觉得有必要做笔记。
常见的如下:
1. 没有方法的类(MissingMethods)。没有方法的类是没有存在价值的,“programs are about behavior!”,我们应该根据行为来划分软件系统。如果不是根据行为来划分软件,说明用了其它错误的划分方法。
2. 真空类(Vapor Classes)。书中有个Light的类,这个类没有数据成员,只有两个方法:on和off,这两个方法也是做了一个简单的转换,方法里只有一句,调用了CoffeeMakerAPI的函数,没有做任何有意义的事,去掉它完全不影响软件逻辑。除了Light外,Button、Boiler和WarmerPlate也是这样的类,去掉对逻辑没有任何影响。
3. 假想的抽象(Imaginary Abstraction)。因为咖啡机的需求描述里提到了几种加热器和传感器,初学者会想当然的弄出一个传感器的抽象基类。如何判断基类是否合理呢?看有没有其它类会用到它。另外,如果抽象类的接口太泛化,也是错误抽象的一个提示。假想的基类之所以出现,是因为大家按照需求规格书,从里面挑名词,然后根据这些名词提取抽象。
4. 神一样的类(God Classes)。如果所有责任都在一个类的身上,也许你创建了一个全能类。全能类是我们要避免的,这就是我们做设计的原因。
提了这么多错误和注意事项,那么,正确的咖啡机程序该如何设计呢?
"The trick to solving this problem is to step back from the problem and separate the
details from the essential nature of the problem. Forget about boilers, valves, heaters, sensors,
and all the little details of the problem and concentrate on the underlying problem.
What is that problem? The problem is: How do you make coffee?
How do you make cofee? The simplest, and most common solution to this problem, is
to pour hot water over coffee grounds, and to collect the resulting infusion in some kind of
vessel. Where do we get the hot water from? Let’s call it a HotWaterSource. Where do
we collect the coffee? Lets call it a ContainmentVessel."
如书中所说,要忽略细节,看清问题的本质。
煮咖啡就是将热水倒在咖啡渣上,然后用个容器接收滤出的水。所以咖啡机由两个东西构成:HotWaterSource和ContainmentVessel。这两个类之间有什么样的依赖关系呢?初学者容易将方位的上下映射到类的依赖中,这是不对的。类的依赖关系应该反映message的流动,其实就是谁给谁发消息。书中将这种连线错误称之为Crossed Wires。
有了这两个类就够了吗?不够。还要添加用户界面,不然用户无法使用咖啡机。为此,作者添加了UserInterface类,负责和用户交互的一切。
这个三元组如何配合呢?怎么样来确定每个类的行为?答案是从行为触发,通过用例来看这三个类之间有哪些消息需要传递。可以用协作图将关系表达出来。完成了动态图之后,可以将静态的类图也画出来。
静态图和动态图都有了,这样就完了吗?我觉得这样就差不多了。但是作者却说“No, No, No”(OK,这一句是我想象的)。
理想中的咖啡壶已经设计好了,马上把它在代码里实现吧!
作者提到,如果将M4咖啡壶的细节掺入刚刚设计好的类中,那么刚才的抽象工作白做了。为了设计可以复用,必须将不能重用的部分分开。所以才有了后面“Use Case 1. User pushes Brew Button (Mark IV)” 等几节。一般书上都是从生活到艺术,这一章作者从艺术到生活,意料,让人耳目一新。