2007年9月19日星期三

抽象类与接口

java里面,在什么情况下你会选择抽象类而不是接口?通常情况下,你能否解释抽象类的含义并说明什么时候使用他们?当你开始设计一个独立的系统的时候,当你准备深入面向对象编程的时候你一定会问自己这些问题。这个问题,乍一看是一个写程序的细节问题,但其实这是一个设计的问题。接口与抽象类的运用能够使你的程序变得更加的抽象,从而更加的灵活,更能够适应变化的需求。我想,这一点至关重要。


从语法的角度来看,抽象类和接口的差别好像仅仅是有没有具体方法的问题,当让这也是一个事实。这种微小的差别使得我们在使用他们的时候差生了疑问。我们会觉得尽然有抽象类为什么还需要接口,如果我把抽象类中的所有方法都定义为抽象的那不是和接口是一样的了么?是的,如果仅从语法的层面来看的却是这样。但事实上他们的用途是完全不同的。


抽象类被设计出来是要用于被继承。当我们设计任何一个抽象类的时候我们都要明白这一点,这个抽象类是被用来继承的。它必然是一个完成某种功能的树的一个根节点。我们可以看一下java中的util里的AbstractList这个抽象类。如下:

java.lang.Object
继承者 java.util.AbstractCollection<E>
继承者 java.util.AbstractList<E>
直接已知子类:
AbstractSequentialList, ArrayList, Vector
我们从来没有直接使用过这个AbstractList。但是我们常用它的子类,比如说Vector。乍一看好像util里面这个抽象类毫无用处,但事实上,如果我们需要自己实现一个特殊的List而有不想封装或者不能封装ArrayList或者Vector的话我们就可以从这继承,来写自己的List。
抽象类必然是一个功能体系的根,它实在有太多的好处。最根本的一条是它能够提供一些规约,用来约束由他派生出来的子类。比如一些共用的资源,共用的算法什么的。例如,假设你所在的公司开发了一套鸭子模拟游戏,它可以模拟各种不同的鸭子,在水上游泳,同时还能发出“嘎嘎”的叫声。我们就可以这样来设计,一个抽象的Duck基类,有发出“嘎嘎”叫声的Quack方法和在水里游泳的Swim方法,同时它还有一个抽象的 Display方法,每一个Duck子类(如MallardDuck、RedheadDuck)都将之重写,以便实现自己与众不同的外观。如下图:

你们公司有很多竞争对手,他们可不是吃素的,在日益增大的市场压力下,你们老板做出了一个决定,要改进这个游戏,让游戏里的鸭子飞起来,成功的话,一定可以打败所有的人。哦,这个艰巨的任务就交给你了。接到任务,你马上就开始了。这还不容易?在Duck基类里加一个Fly方法,这样所有的Duck子类都可以获得这个方法,所有的鸭子都可以飞了。太简单了,这就是抽象类的威力呀。

所以,抽象类就应该这么用。它生来就是要被继承的。如果不需要继承也就同样不需要抽象类。当然我们遇到的问题不可能如此的简单,往往具体的问题需要具体的分析才能真正的解决。而这个解决也同样不可能是完美的。这里我又想提一提Martin Fowler的《The New Methodology》这篇文章,里面谈到了很多。因为我们的软件不可能都像NASA的航天飞机的软件开发项目那样拥有不变而且确定的需求和在这个基础上完美的设计的。所以对我们系统的合理抽象可以说是至关重要的。就如同上面的鸭子项目一样,合理的抽象使我们面对变化而从容不迫。试想如果我们没有这个抽象会怎么样?一个类一个类的去改代码?那我们面对的就是一片森林了。项目因此就有可能陷入泥潭。

那么我们再来说说接口,接口有什么用处呢?其实接口也是为了应对变化而出现的。不过这个变化和上面的不同,接口应对的是可以预知的变化。也就是说,在我们设计系统的时候,我们知道这个地方一定会有变化,我们就可以采用接口的方式把这个变化保留下来。当然接口的目的是要和其他的对象进行配合的,如果你预料到的这个变化和系统的其他部分没有什么关系的话,那我认为你没有必要考虑它了。举个例子:java.io中的
FilenameFilter极为典型。我们只需要实现boolean accept(File dir, String name)方法,系统就可以根据我们的要求来进行过滤了。这里我还想提一个典型的错误接口设计,那就是常数接口,吧一堆常数放到接口里面去,需要的时候就让自己的对象来实现。这是一种晕头的设计。我的建议是不妨另写一个类就起名叫Constents好了,把所有的常数放到它里面。

其实抽象类和接口在jdk里面是在是非常的多。很多类包的设计都是含有若干接口若干抽象类的。可以知道,实际的系统往往是比较复杂的,如何设计其实取决于我们如何理解的系统,理解的是否正确。另外我们的设计也要充分合理的考虑到变化,不要去搞一锤子买卖。在软件设计中这个很不现实。毕竟人们对一个系统的认识不可能一步到位的。当然要应对变化,仅仅是抽象还是不够的,但这毕竟是最基本的。

没有评论: