设计模式我们已经学习了好长的时间了,对于使用设计模式的好处这里不再多说了,本文主要总结一下关于在面向对象过程中体现的动态扩展的源泉——抽象类的继承和接口的实现。
一、为什么要使用到抽象类或者是接口
我们为什么要使用设计模式呢?使用了设计模式之后,我们可以很方便的通过增加类和几行代码来解决功能或者策略的添加问题。那么是如何实现的呢,这里我们就要谈到抽象类和接口了。
我们可以翻翻设计模式的书看看,是不是在每个模式中都会出现抽象类或者是接口的身影呢?我们用到这些东西都是在做什么?
我们可能会经常看到如下图类似的UML图部分:
这种地方是不是总是出现抽象或者接口,我们是不是常用他们来进行扩展,最头上的总是接口,或者抽象类,下面的点总是接口实现的几种方式,或者是抽象类泛化出来的一些派生类。既然他们都是这样可以扩展的,我们又要在什么情况下使用他们呢?
二、抽象类和接口的使用
我们使用抽象类和接口都可以对于一个功能进行扩展,进行分布化编写,那么具体要怎么用呢?
我们首先需要考虑的是对于抽象类的继承,和接口的实现,他们都有什么特性?有什么异同点?
相同点:
他们都具有某些函数在其中,其子类或者实现都需要去重写或者实现他们没有实现的部分(接口完全不实现),要求返回值和参数和定义中的必须是一致的。并且最大的相同点是一个抽象类可以被N个子类继承,一个接口也可以被N个实现类所实现。
不同点:
在抽象类中,我们可以定义公共的方法和变量,在子类中可以写父类中没有出现过的变量或者方法,而接口中则不同,接口的实现类必须按部就班的去实现,不能多方法,也不能少方法,并且没有一个统一的,可以公共使用的变量或者方法。并且抽象类的继承是单独的,但是一个实现却能实现好多的接口。
1、从编程的角度来看,abstract class和interface都可以用来实现 "design by contract" 的思想。但是在具体的使用上面还是有一些区别的。
首先,abstract class 在 Java 语言中表示的是一种继承关系,一个类只能使用一次继承关系(因为Java不支持多继承 -- 转注)。但是,一个类却可以实现多个interface。也许,这是Java语言的设计者在考虑Java对于多重继承的支持方面的一种折中考虑吧。
其次,在abstract class的定义中,我们可以赋予方法的默认行为。但是在interface的定义中,方法却不能拥有默认行为,为了绕过这个限制,必须使用委托,但是这会增加一些复杂性,有时会造成很大的麻烦。
在抽象类中不能定义默认行为还存在另一个比较严重的问题,那就是可能会造成维护上的麻烦。因 为如果后来想修改类的界面(一般通过 abstract class 或者interface来表示)以适应新的情况(比如,添加新的方法或者给已用的方法中添 加新的参数)时,就会非常的麻烦,可能要花费很多的时间(对于派生类很多的情况,尤为如此)。但是如果界面是通过abstract class来实现的,那 么可能就只需要修改定义在abstract class中的默认行为就可以了。
同样,如果不能在抽象类中定义默认行为,就会导致同样的方法实现出现在该抽象类的每一个派生类中,违反了 "one rule,one place" 原则,造成代码重复,同样不利于以后的维护。因此,在abstract class和interface间进行选择时要非常的小心。
三、总结
1.在abstract class 中可以有自己的数据成员,也可以有非abstarct的成员方法,而在interface中,只能够有静态的不能被修改的数据成员(也就是必须是static final的,不过在 interface中一般不定义数据成员),所有的成员方法都是abstract的。
2.abstract class和interface所反映出的设计理念不同。其实abstract class表示的是"is-a"关系,interface表示的是"like-a"关系。
3.实现抽象类和接口的类必须实现其中的所有方法。抽象类中可以有非抽象方法。接口中则不能有实现方法。
4.接口中定义的变量默认是public static final 型,且必须给其初值,所以实现类中不能重新定义,也不能改变其值。
5.抽象类中的变量默认是 friendly 型,其值可以在子类中重新定义,也可以重新赋值。
6.接口中的方法默认都是 public,abstract 类型的。