??xml version="1.0" encoding="utf-8" standalone="yes"?>
理解抽象c?
abstract class和interface在Java语言中都是用来进行抽象类Q本文中的抽象类q从abstract class译而来Q它表示的是一个抽象体Q而abstract class为Java语言中用于定义抽象类的一U方法,误者注意区分)(j)定义的,那么什么是抽象c,使用抽象c能为我们带来什么好处呢Q?
在面向对象的概念中,我们知道所有的对象都是通过cL描绘的,但是反过来却不是q样。ƈ不是所有的c都是用来描l对象的Q如果一个类中没有包含够的信息来描l(sh)个具体的对象Q这L(fng)cd是抽象类。抽象类往往用来表征我们在对问题领域q行分析、设计中得出的抽象概念,是对一pd看上M同,但是本质上相同的具体概念的抽象。比如:(x)如果我们q行一个图形编辑Y件的开发,׃(x)发现问题领域存在着圆、三角Şq样一些具体概念,它们是不同的Q但是它们又都属于Ş状这样一个概念,形状q个概念在问题领域是不存在的Q它?yu)是一个抽象概c(din)正是因为抽象的概念在问题领域没有对应的具体概念Q所以用以表征抽象概늚抽象cL不能够实例化的?
在面向对象领域,抽象cM要用来进行类型隐藏。我们可以构造出一个固定的一l行为的抽象描述Q但是这l行为却能够有Q意个可能的具体实现方式。这个抽象描q就是抽象类Q而这一lQ意个可能的具体实现则表现为所有可能的zcR模块可以操作一个抽象体。由于模块依赖于一个固定的抽象体,因此它可以是不允怿改的Q同Ӟ通过从这个抽象体zQ也可扩展此模块的行为功能。熟(zhn)OCP的读者一定知道,Z(jin)能够实现面向对象设计的一个最核心(j)的原则OCP(Open-Closed Principle)Q抽象类是其中的关键所在?
从语法定义层面看abstract class和interface
在语法层面,Java语言对于abstract class和interfacel出?jin)不同的定义方式Q下面以定义一个名为Demo的抽象类Z来说明这U不同?
使用abstract class的方式定义Demo抽象cȝ方式如下Q?
abstract class Demo {
abstract void method1();
abstract void method2()
?
}
(tng)
使用interface的方式定义Demo抽象cȝ方式如下Q?
interface Demo {
void method1();
void method2();
?br />}
(tng)
在abstract class方式中,Demo可以有自q数据成员Q也可以有非abstarct的成员方法,而在interface方式的实CQDemo只能够有?rn)态的不能被修改的数据成员Q也是必须是static final的,不过在interface中一般不定义数据成员Q,所有的成员Ҏ(gu)都是abstract的。从某种意义上说Qinterface是一U特DŞ式的abstract class?
从编E的角度来看Qabstract class和interface都可以用来实?design by contract"的思想。但是在具体的用上面还是有一些区别的?
首先Qabstract class在Java语言中表C的是一U承关p,一个类只能使用一ơ承关pR但是,一个类却可以实现多个interface。也许,q是Java语言的设计者在考虑Java对于多重l承的支持方面的一U折?sh)考虑吧?
其次Q在abstract class的定义中Q我们可以赋予方法的默认行ؓ(f)。但是在interface的定义中Q方法却不能拥有默认行ؓ(f)Qؓ(f)?jin)绕q这个限Ӟ必须使用委托Q但是这?增加一些复杂性,有时?x)造成很大的麻?ch)?
在抽象类中不能定义默认行存在另一个比较严重的问题Q那是可能?x)造成l护上的ȝ(ch)。因为如果后来想修改cȝ界面Q一般通过abstract class或者interface来表C)(j)以适应新的情况Q比如,d新的Ҏ(gu)或者给已用的方法中d新的参数Q时Q就?x)非常的ȝ?ch)Q可能要p很多的时_(d)对于zcd多的情况Q尤为如此)(j)。但是如果界面是通过abstract class来实现的Q那么可能就只需要修改定义在abstract class中的默认行ؓ(f)可以了(jin)?
同样Q如果不能在抽象cM定义默认行ؓ(f)Q就?x)导致同L(fng)Ҏ(gu)实现出现在该抽象cȝ每一个派生类中,q反?one ruleQone place"原则Q造成代码重复Q同样不利于以后的维护。因此,在abstract class和interface间进行选择时要非常的小?j)?
从设计理念层面看abstract class和interface
上面主要从语法定义和~程的角度论qC(jin)abstract class和interface的区别,q些层面的区别是比较低层ơ的、非本质的。本节从另一个层面:(x)abstract class和interface所反映出的设计理念Q来分析一下二者的区别。作者认为,从这个层面进行分析才能理解二者概늚本质所在?
前面已经提到q,abstarct class在Java语言中体C(jin)一U承关p,要想使得l承关系合理Q父cdzcM间必d?is a"关系Q即父类和派生类在概忉|质上应该是相同的Q参考文献?〕中有关?is a"关系的大幅深入的论qͼ有兴的读者可以参考)(j)。对于interface 来说则不?dng)q不要求interface的实现者和interface定义在概忉|质上是一致的Q仅仅是实现?jin)interface定义的契U而已。ؓ(f)?jin)便于理解Q下面将通过一个简单的实例q行说明?
考虑q样一个例子,假设在我们的问题领域中有一个关于Door的抽象概念,该Doorh执行两个动作open和closeQ此时我们可以通过abstract class或者interface来定义一个表C抽象概念的类型,定义方式分别如下所C:(x)
使用abstract class方式定义DoorQ?
abstract class Door {
abstract void open();
abstract void close()Q?
}
(tng)
使用interface方式定义DoorQ?
(tng)
interface Door {
void open();
void close();
}
(tng)
其他具体的Doorcd可以extends使用abstract class方式定义的Door或者implements使用interface方式定义的Door。看h好像使用abstract class和interface没有大的区别?
如果现在要求Doorq要h报警的功能。我们该如何设计针对该例子的cȝ构呢Q在本例中,主要是ؓ(f)?jin)展Cabstract class和interface反映在设计理念上的区别,其他斚w无关的问题都做了(jin)化或者忽略)(j)Q下面将|列出可能的解决Ҏ(gu)Qƈ从设计理念层面对q些不同的方案进行分析?
解决Ҏ(gu)一Q?
单的在Door的定义中增加一个alarmҎ(gu)Q如下:(x)
(tng)
abstract class Door {
abstract void open();
abstract void close()Q?
abstract void alarm();
}
(tng)
或?
(tng)
interface Door {
void open();
void close();
void alarm();
}
(tng)
那么h报警功能的AlarmDoor的定义方式如下:(x)
(tng)
class AlarmDoor extends Door {
void open() { ?}
void close() { ?}
void alarm() { ?}
}
(tng)
或?
(tng)
class AlarmDoor implements Door {
void open() { ?}
void close() { ?}
void alarm() { ?}
}
(tng)
q种Ҏ(gu)q反?jin)面向对象设计中的一个核?j)原则ISPQInterface Segregation PricipleQ,在Door的定义中把Door概念本n固有的行为方法和另外一个概?报警?的行为方法在了(jin)一赗这样引L(fng)一个问题是那些仅仅依赖于Doorq个概念的模块会(x)因ؓ(f)"报警?q个概念的改变(比如Q修改alarmҎ(gu)的参敎ͼ(j)而改变,反之依然?
解决Ҏ(gu)二:(x)
既然open、close和alarm属于两个不同的概念,Ҏ(gu)ISP原则应该把它们分别定义在代表q两个概늚抽象cM。定义方式有Q这两个概念都用abstract class方式定义Q两个概念都使用interface方式定义Q一个概念用abstract class方式定义Q另一个概念用interface方式定义?
昄Q由于Java语言不支持多重承,所以两个概念都使用abstract class方式定义是不可行的。后面两U方式都是可行的Q但是对于它们的选择却反映出对于问题领域中的概念本质的理解、对于设计意囄反映是否正确、合理。我们一一来分析、说明?
如果两个概念都用interface方式来定义,那么反映出两个问题Q?、我们可能没有理解清楚问题领域,AlarmDoor在概忉|质上到底是Doorq是报警器?2、如果我们对于问题领域的理解没有问题Q比如:(x)我们通过对于问题领域的分析发现AlarmDoor在概忉|质上和Door是一致的Q那么我们在实现时就没有能够正确的揭C我们的设计意图Q因为在q两个概늚定义上(均用interface方式定义Q反映不Zq含义?/p>
如果我们对于问题领域的理解是QAlarmDoor在概忉|质上是DoorQ同时它有具有报警的功能。我们该如何来设计、实现来明确的反映出我们的意思呢Q前面已l说q,abstract class在Java语言中表CZU承关p,而承关pd本质上是"is a"关系。所以对于Doorq个概念Q我们应该用abstarct class方式来定义。另外,AlarmDoor又具有报警功能,说明它又能够完成报警概念中定义的行ؓ(f)Q所以报警概念可以通过interface方式定义。如下所C:(x)
(tng)
abstract class Door {
abstract void open();
abstract void close()Q?br />}
interface Alarm {
void alarm();
}
class AlarmDoor extends Door implements Alarm {
void open() { ?}
void close() { ?}
void alarm() { ?}
}
(tng)
q种实现方式基本上能够明的反映出我们对于问题领域的理解Q正的揭示我们的设计意图。其实abstract class表示的是"is a"关系Qinterface表示的是"like a"关系Q大家在选择时可以作Z个依据,当然q是建立在对问题领域的理解上的,比如Q如果我们认为AlarmDoor在概忉|质上是报警器Q同时又hDoor的功能,那么上述的定义方式就要反q来?jin)?/p>
l论
abstract class和interface是Java语言中的两种定义抽象cȝ方式Q它们之间有很大的相似性。但是对于它们的选择却又往往反映出对于问题领域中的概忉|质的理解、对于设计意囄反映是否正确、合理,因ؓ(f)它们表现?jin)概念间的不同的关系Q虽焉能够实现需求的功能Q。这其实也是语言的一U的惯用法,希望读者朋友能够细l体?x)?br />