抽象类 是对一系列看上去不同,但是本质上相同的具体概念的抽象。
在语法层面,
Java语言对于abstract class和interface给出了不同的定义方式:
abstract class方式定义:
abstract class Demo
{
int num1;
abstract int num2;
abstract void method1();
abstract void method2();
}
interface Demo
{
static final int num;
void method1();
interface method2();
}
interface 中只能有 静态的、不能修改的 数据成员(static final),但是在interface中一般不定义数据成员。interface 中所有成员方法都是abstract的。interface是一种特殊形式的abstract class.
首先,abstract class在java语言中表示 “一种继承关系”(即,需要用到extends关键字),一个类只能单继承(java不支持多继承),但可 实现多个interface(即,需要用到implements关键字)。PS:为了弥补无法多继承的缺陷。
其次,abstract class可以赋予方法 默认行为,但interface中,方法不能拥有默认行为。
如果不能再抽象类中定义默认行为,就会导致 “同样的方法实现” 出现在该抽象类的每一个派生类中,造成代码重复,同样不利于以后维护。
设计理念层面,
abstract class在应用时,必须保证“is-a”(父子继承关系B is a A.);而interface应用时,并不要求interface的实现者 与 interface存在"is-a"关系,只需实现interface定义的契约即可(是一种“like-a”关系)。
案例:抽象一个Door类,用以Security_Door类继承。(abstract class和interface两种方式对比)。
abstract class Door
{
abstract void open();
abstract void close();
}
interface Door
{
void open();
void close();
}
现在,Security_Door需要一个门铃功能。有三种方案:
1、简单的在Door抽象类中添加alarm()方法:
abstract class Door
{
abstract void open();
abstract void close();
abstract void alarm();
}
interface Door
{
void open();
void close();
void alarm();
}
这样定义Door,导致 将Door的固有行为 与 另外一个功能Alarm行为 混在一起。
从而导致,有些仅依赖于Door固有行为 的模块,贅余上Alarm行为。若Alarm行为改变,导致仅依赖Door固有行为的模块也随之强迫、无用的 改变。
这也正是ISP(接口分离原则)所否定的!
2、open()、close()和alarm()属于 两个不同的 概念,根据ISP原则,应该把它们 分别定义 两个抽象类中。
理论上可以:
(1) 这两个概念都用 abstract class 方式定义。(java不支持多继承,故不可行!)
(2) 这两个概念都使用 interface 方式定义。 (先确定继承者的本质,Door Or Alarm。从而知道谁是主体,谁是附属,明确显示出设计意图。显然这种方式doubleinterface不能表明)
(3) 一个用abstract class定义,一个用interface定义。(Security_Door extends Door implements Alarm合理!)
abstract class Door
{
abstract void open();
abstract void close();
}
interface Alarm
{
void alarm();
}
class Security_Door extends Door implements Alarm
{
void open();
void close();
void alarm();
}
附注:
1.abstract class 在 Java 语言中表示的是一种继承关系,一个类只能使用一次继承关系。但是,一个类却可以实现多个interface。
2.在abstract class 中可以有自己的数据成员(only public, protected, private, static, final, transient & volatile),而在interface中,只能够有静态的不能被修改的数据成员(也就是必须是static final的,不过在 interface中一般不定义数据成员)。
3.在abstract class 中成员方法可以有 abstract方法(不能有方法体) 和 非abstract方法(可以有方法体),继承abstract class时必须实现 所有abstract方法;而在interface中成员方法(不能有方法体)(only public & abstract,声明成public还是abstract没有区别,所以直接不用public/abstract修饰即可,因此其默认是public还是abstract也没有探究必要了。个人猜测,用public、abstract或者public abstract 修饰是同一效果,总之,肯定是abstract的,因为不允许有方法体),实现interface时,必须实现 所有成员方法。
4.abstract class和interface所反映出的设计理念不同。其实abstract class表示的是"is-a"关系,interface表示的是"like-a"关系。
5.接口中定义的变量默认是public static final 型,且必须给其初值,所以实现类中不能重新定义,也不能改变其值。
6.抽象类中的变量默认是 friendly 型,其值可以在子类中重新定义,也可以重新赋值。
7.接口中的方法默认都是 public,abstract 类型的。(有歧义)
ISP(Interface Segregation Principle 接口隔离原则)
一、定义
讲接口隔离原则,它有两种定义:
第一种定义: Clients should not beforced to depend upon interfaces that they don't use.
客户端不应该依赖它不需用的接口。
第二种定义:The dependency of oneclass to another one should depend on the smallest possible interface。
类间的依赖关系应该建立在最小的接口上。
二、解释
第一种定义客户端不应该依赖它不需要接口,那依赖什么?依赖它需要的接口,客户端需要什么接口就提供什么接口,把不需要的接口剔除掉,那就需要对接口进行细化,保证其纯洁性;
第二个定义,类间的依赖关系应该建立在最小的接口上,它要求是最小的接口,也是要求接口细化,接口纯洁,与第一个定义如出一辙,只是一个事物的两种不同描述。