一.

类是面向对象的基础。面向对象有三大特点:封装,继承和多态。

我们学习面向对象,不可回避几部经典,比如C++编程,编程思想等。

无论Java还是C++,只要讲解面向对象,都会有一些例子用来说明什么是封装,继承和多态。

大部分都会用shape来举例。

shape作为抽象的基类,circle,square和triangle继承自shape。shape会有个draw的函数,多半还是个虚函数。

这样的例子对初学者来说也是简单易懂的,很能说明白面向对象是什么。

但这却是一个非常糟糕的开端,就像小时候父母告诉你是从胳肢窝里出来的一样,从一开始就给了你一个错误的概念。

二.

面向对象的产生,不仅仅是为了解决问题,还应该要站在待解决问题的角度来描述问题,从而让问题本身更容易被理解和解决。

换个说法,就是我们应该如实的描述问题,不夸张不过分。

什么是夸张?你从胳肢窝里出来就是夸张。shape有个draw的函数,也是夸张。你见过一个会draw自己的shape?

有人认为这无伤大雅,把draw放在shape中,能更简洁的解决问题。

但我们应该从一开始就建立一个正确的概念。

三.

然而把draw放在shape中并不能简洁的解决问题。

我们需要在真实的环境中使用这些类,比如Microsoft Windows。我们使用GDI来画这些shape。我们需要一个DC。

怎么表示?在shape中聚合一个HDC,还是把HDC作为参数传递给draw?(应该没有人会让shape从DC继承吧?)

我们还需要一个画笔,来表达这个shape的其他属性,比如颜色,粗细等。

我们还需要知道位置,这个shape在DC上的位置。

问题开始变得复杂了,shape类以及它的子类与GDI对象耦合在一起。

四.

shape类以及它的子类本应该是独立的。

cycle在在Windows下是cycle,在Linux下也应该是cycle,不管有没有GDI对象。

问题出在什么地方?

在这个例子中显而易见:只有在真正开始draw的时候,才需要GDI对象,而shape本身,并不能做draw这件事情。

把一件不能做的事情,或是不适合做的事情硬塞给对象来实现,迟早是会出问题的。

最糟糕的不是我们发现不了问题,而恰恰是问题迟早会被发现。

五.

如何从一开始就避免这样的情况,而不是在第二次的时候才做正确?

我们如何才能够设计出一个正确的类?或者更确切的说,如何才能够正确的设计出一个类?

从一开始就如实的描述问题,不夸张不过分。不给它不拥有的属性,更不给它不应该有的父类。

这是最基本的设计原则。

六.

对于设计现实中不存在对应的类,同样需要如实描述——如实描述想法,设计。不要想的是孙悟空,出来的却是二郎神。

计算机只识别0和1,这是个讲究精确的行业。

Comments

2010-02-20