[转]抽象类,还是接口?

抽象类,还是接口?

抽象类和接口都属于以上提到的抽象,两者的在语法上的区别Anytao和其他园友已经总结的差不多了,不再赘述。我主要想和大家讨论一下在设计时如何选择抽象类和接口。

我的原则是,尽量按照现实世界的语义来判断。

众所周知,派生类与抽象类的关系是IS-A,实现类与接口的关系是CAN-DO。这就说明抽象类与子类之间的所属关系较接口来说更加明确。接口只是行为方式上的一种契约,一个类实现了一个接口,只能说明该类具有该接口所约定的行为,但它并不属于该接口(事实上,接口也无法成为其他类的所属者),因此我们把对抽象类的派生叫做继承,而把对接口的派生叫做实现。例如,IComparable接口为所有可进行比较的类提供一个抽象的约定,但也仅仅局限于该约定。在语义上,“可以比较的”并不是某一类事物全部行为和属性的抽象,因此并不能够成为其派生类的父类。

人和汽车肯定不属于一类事物,但是他们却可以有相同的行为,即Move。那么Person类和Car类虽然继承自不同的基类,但它们却可以实现同一个接口IMoveable(该接口仅包含一个Move方法)。

因此,在设计时,我们需要思考这个抽象是代表的一类事物,还是代表一类行为或属性。如果是一类事物,就设计为抽象类;如果是一类行为或属性,就设计为接口。如果发现某个子类不得不继承两个基类,那么就必须审视一下这两个基类的设计是否合理,是否应该提取一些接口出来,或者是否应该重新设计一个基类。

现在来回答为什么接口不能有实现的问题,因为现实世界……哎呀,哪里的砖头?……

呵呵,其实正如前面所说,接口只是一种规范的约定,它并不了解各个实现类的具体细节。抽象类Person可以对Move方法提供默认实现(走或跑),Car也同样可以(前进或倒退),但是IMoveable接口并不知道,能实现这个接口的类成千上万并且实现方式千奇百怪,要它提供一个默认的移动方式,实在强接口所难。

对于命名的建议

对于抽象类和接口的命名规范,我的建议是:将抽象类(类也是如此)命名为名词,将接口命名为I为前缀的形容词,最好以-able为后缀。

在.NET Framework里随处可见以-able为后缀的接口,如IComparable、IDisposable……意为“可……的”,这完全复合CAN-DO的语义定义。前面的IMoveable接口如果命名为IMove,在语义上或多或少地缺少了CAN-DO的意境。

当然,这只是一种建议。只要牢记接口是“可……的”这个原则,在选择抽象类和接口时就不会感到茫然了。

总之一句话,请参考现实世界。

posted @ 2010-10-28 15:12  zhdonghu  阅读(191)  评论(0编辑  收藏  举报