??xml version="1.0" encoding="utf-8" standalone="yes"?>日韩av一区二区三区四区,蜜臀av在线播放,99在线观看视频http://www.aygfsteel.com/jsdk999/category/17766.htmlzh-cnFri, 02 Mar 2007 03:17:43 GMTFri, 02 Mar 2007 03:17:43 GMT60- 看到一遍好文章啊,大家分n下!--抽象cd接口的用场?/title>http://www.aygfsteel.com/jsdk999/archive/2006/09/22/71274.htmlWindDCWindDCFri, 22 Sep 2006 03:32:00 GMThttp://www.aygfsteel.com/jsdk999/archive/2006/09/22/71274.htmlhttp://www.aygfsteel.com/jsdk999/comments/71274.htmlhttp://www.aygfsteel.com/jsdk999/archive/2006/09/22/71274.html#Feedback0http://www.aygfsteel.com/jsdk999/comments/commentRss/71274.htmlhttp://www.aygfsteel.com/jsdk999/services/trackbacks/71274.html
理解抽象c?br />
abstract class和interface在Java语言中都是用来进行抽象类Q本文中的抽象类q从abstract class译而来Q它表示的是一个抽象体Q而abstract class为Java语言中用于定义抽象类的一U方法,误者注意区分)定义的,那么什么是抽象c,使用抽象c能为我们带来什么好处呢Q?br />
在面向对象的概念中,我们知道所有的对象都是通过cL描绘的,但是反过来却不是q样。ƈ不是所有的c都是用来描l对象的Q如果一个类中没有包含够的信息来描l一个具体的对象Q这Lcd是抽象类。抽象类往往用来表征我们在对问题领域q行分析、设计中得出的抽象概念,是对一pd看上M同,但是本质上相同的具体概念的抽象。比如:如果我们q行一个图形编辑Y件的开发,׃发现问题领域存在着圆、三角Şq样一些具体概念,它们是不同的Q但是它们又都属于Ş状这样一个概念,形状q个概念在问题领域是不存在的Q它是一个抽象概c正是因为抽象的概念在问题领域没有对应的具体概念Q所以用以表征抽象概늚抽象cL不能够实例化的?br />
在面向对象领域,抽象cM要用来进行类型隐藏。我们可以构造出一个固定的一l行为的抽象描述Q但是这l行为却能够有Q意个可能的具体实现方式。这个抽象描q就是抽象类Q而这一lQ意个可能的具体实现则表现为所有可能的zcR模块可以操作一个抽象体。由于模块依赖于一个固定的抽象体,因此它可以是不允怿改的Q同Ӟ通过从这个抽象体zQ也可扩展此模块的行为功能。熟悉OCP的读者一定知道,Z能够实现面向对象设计的一个最核心的原则OCP(Open-Closed Principle)Q抽象类是其中的关键所在?br />
从语法定义层面看abstract class和interface
在语法层面,Java语言对于abstract class和interfacel出了不同的定义方式Q下面以定义一个名为Demo的抽象类Z来说明这U不同?br />
使用abstract class的方式定义Demo抽象cȝ方式如下Q?br />
abstract class Demo ?br />abstract void method1();
abstract void method2();
?br />?br />
使用interface的方式定义Demo抽象cȝ方式如下Q?br />
interface Demo {
void method1();
void method2();
?br />}
在abstract class方式中,Demo可以有自q数据成员Q也可以有非abstarct的成员方法,而在interface方式的实CQDemo只能够有静态的不能被修改的数据成员Q也是必须是static final的,不过在interface中一般不定义数据成员Q,所有的成员Ҏ都是abstract的。从某种意义上说Qinterface是一U特DŞ式的abstract class?br />
从编E的角度来看Qabstract class和interface都可以用来实现design by contract的思想。但是在具体的用上面还是有一些区别的?br />
首先Qabstract class在Java语言中表C的是一U承关p,一个类只能使用一ơ承关pR但是,一个类却可以实现多个interface。也许,q是Java语言的设计者在考虑Java对于多重l承的支持方面的一U折中考虑吧?br />
其次Q在abstract class的定义中Q我们可以赋予方法的默认行ؓ。但是在interface的定义中Q方法却不能拥有默认行ؓQؓ了绕q这个限Ӟ必须使用委托Q但是这?增加一些复杂性,有时会造成很大的麻烦?br />
在抽象类中不能定义默认行存在另一个比较严重的问题Q那是可能会造成l护上的ȝ。因为如果后来想修改cȝ界面Q一般通过abstract class或者interface来表C)以适应新的情况Q比如,d新的Ҏ或者给已用的方法中d新的参数Q时Q就会非常的ȝQ可能要p很多的时_对于zcd多的情况Q尤为如此)。但是如果界面是通过abstract class来实现的Q那么可能就只需要修改定义在abstract class中的默认行ؓ可以了?br />同样Q如果不能在抽象cM定义默认行ؓQ就会导致同LҎ实现出现在该抽象cȝ每一个派生类中,q反?one ruleQone place原则Q造成代码重复Q同样不利于以后的维护。因此,在abstract class和interface间进行选择时要非常的小心?br />
从设计理念层面看abstract class和interface
上面主要从语法定义和~程的角度论qCabstract class和interface的区别,q些层面的区别是比较低层ơ的、非本质的。本节从另一个层面:abstract class和interface所反映出的设计理念Q来分析一下二者的区别。作者认为,从这个层面进行分析才能理解二者概늚本质所在?br />
前面已经提到q,abstarct class在Java语言中体C一U承关p,要想使得l承关系合理Q父cdzcM间必d在is a关系Q即父类和派生类在概忉|质上应该是相同的Q参考文献?〕中有关于is a关系的大幅深入的论qͼ有兴的读者可以参考)。对于interface 来说则不Ӟq不要求interface的实现者和interface定义在概忉|质上是一致的Q仅仅是实现了interface定义的契U而已。ؓ了便于理解Q下面将通过一个简单的实例q行说明?br />
考虑q样一个例子,假设在我们的问题领域中有一个关于Door的抽象概念,该Doorh执行两个动作open和closeQ此时我们可以通过abstract class或者interface来定义一个表C抽象概念的类型,定义方式分别如下所C:
使用abstract class方式定义DoorQ?br />
abstract class Door {
abstract void open();
abstract void close()Q?br />}
使用interface方式定义DoorQ?br />interface Door {
void open();
void close();
}
其他具体的Doorcd可以extends使用abstract class方式定义的Door或者implements使用interface方式定义的Door。看h好像使用abstract class和interface没有大的区别?br />如果现在要求Doorq要h报警的功能。我们该如何设计针对该例子的cȝ构呢Q在本例中,主要是ؓ了展Cabstract class和interface反映在设计理念上的区别,其他斚w无关的问题都做了化或者忽略)Q下面将|列出可能的解决ҎQƈ从设计理念层面对q些不同的方案进行分析?br />
解决Ҏ一Q?br />单的在Door的定义中增加一个alarmҎQ如下:
abstract class Door {
abstract void open();
abstract void close()Q?br />abstract void alarm();
}
或?br />interface Door {
void open();
void close();
void alarm();
}
那么h报警功能的AlarmDoor的定义方式如下:
class AlarmDoor extends Door {
void open() { ?}
void close() { ?}
void alarm() { ?}
}
或?br />class AlarmDoor implements Door ?br />void open() { ?}
void close() { ?}
void alarm() { ?}
?br />q种Ҏq反了面向对象设计中的一个核心原则ISPQInterface Segregation PricipleQ,在Door的定义中把Door概念本n固有的行为方法和另外一个概忉|警器的行为方法在了一赗这样引L一个问题是那些仅仅依赖于Doorq个概念的模块会因ؓ报警器这个概늚改变Q比如:修改alarmҎ的参敎ͼ而改变,反之依然?br />
解决Ҏ二:
既然open、close和alarm属于两个不同的概念,ҎISP原则应该把它们分别定义在代表q两个概늚抽象cM。定义方式有Q这两个概念都?abstract class方式定义Q两个概念都使用interface方式定义Q一个概念用abstract class方式定义Q另一个概念用interface方式定义?br />
昄Q由于Java语言不支持多重承,所以两个概念都使用abstract class方式定义是不可行的。后面两U方式都是可行的Q但是对于它们的选择却反映出对于问题领域中的概念本质的理解、对于设计意囄反映是否正确、合理。我们一一来分析、说明?br />
如果两个概念都用interface方式来定义,那么反映出两个问题Q?、我们可能没有理解清楚问题领域,AlarmDoor在概忉|质上到底?Doorq是报警器?2、如果我们对于问题领域的理解没有问题Q比如:我们通过对于问题领域的分析发现AlarmDoor在概忉|质上和Door是一致的Q那么我们在实现时就没有能够正确的揭C我们的设计意图Q因为在q两个概늚定义上(均用interface方式定义Q反映不Zq含义?br />
如果我们对于问题领域的理解是QAlarmDoor在概忉|质上是DoorQ同时它有具有报警的功能。我们该如何来设计、实现来明确的反映出我们的意思呢Q前面已l说q,abstract class在Java语言中表CZU承关p,而承关pd本质上是is a关系。所以对于Doorq个概念Q我们应该用abstarct class方式来定义。另外,AlarmDoor又具有报警功能,说明它又能够完成报警概念中定义的行ؓQ所以报警概念可以通过interface方式定义。如下所C:
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() { ?}
}
q种实现方式基本上能够明的反映出我们对于问题领域的理解Q正的揭示我们的设计意图。其实abstract class表示的是is a关系Qinterface表示的是like a关系Q大家在选择时可以作Z个依据,当然q是建立在对问题领域的理解上的,比如Q如果我们认为AlarmDoor在概忉|质上是报警器Q同时又h Door的功能,那么上述的定义方式就要反q来了?br />l论
abstract class和interface是Java语言中的两种定义抽象cȝ方式Q它们之间有很大的相似性。但是对于它们的选择却又往往反映出对于问题领域中的概忉|质的理解、对于设计意囄反映是否正确、合理,因ؓ它们表现了概念间的不同的关系Q虽焉能够实现需求的功能Q。这其实也是语言的一U的惯用法,希望读者朋友能够细l体会?br />
很多人有q这L疑问Qؓ什么有的地方必M用接口而不是抽象类Q而在另一些地方,又必M用抽象类而不是接口呢Q或者说Q在考虑Javacȝ一般化问题Ӟ很多Z在接口和抽象cM间犹豫不冻I甚至随便选择一U?br />
实际上接口和抽象cȝ选择不是随心所Ʋ的?要理解接口和抽象cȝ选择原则Q有两个概念很重要:对象的行为和对象的实现。如果一个实体可以有多种实现方式Q则在设计实体行为的描述方式Ӟ应当辑ֈq样一个目标:在用实体的时候,无需详细了解实体行ؓ的实现方式。也是_要把对象的行为和对象的实现分d来。既然Java的接口和抽象c都可以定义不提供具体实现的ҎQ在分离对象的行为和对象的实现时Q到底应该用接口还是用抽象类呢?
通过抽象cd立行为模?br />
在接口和抽象cȝ选择上,必须遵守q样一个原则:行ؓ模型应该L通过接口而不是抽象类定义。ؓ了说明其原因Q下面试着通过抽象cd立行为模型,看看会出C么问题?br />
假设要ؓ销售部门设计一个YӞq个软g包含一个“发动机”(MotorQ实体。显然无法在发动机对象中详细地描q发动机的方斚w面,只能描述某些对当前Y件来说重要的特征。至于发动机的哪些特征是重要的,则要与用P销售部门)交流才能定?br />
销售部门的求每一个发动机都有一个称为马力的参数。对于他们来_q是惟一值得兛_的参数。基于这一判断Q可以把发动机的行ؓ定义Z下行为?br />
行ؓ1Q查询发动机的马力,发动机将q回一个表C马力的整数?br />
虽然现在q不清楚发动机如何取得马力这个参敎ͼ但可以肯定发动机一定支持这个行为,而且q是所有发动机惟一值得x的行为特征。这个行为特征既可以用接口定义,也可以用抽象cd义。ؓ了说明用抽象cd义可能出现的问题Q下面用抽象cd立发动机的行为模型,q用JavaҎ描述行ؓ1Q代码如下:
public abstract Motor{
abstract public int getHorsepower();
}
在Motor抽象cȝ基础上构造出多种具体实现Q例如A型发动机、B型发动机{,再加上系l的其它部分Q最后得?.0版的软gq交付用。一D|间过MQ现在要设计2.0版的软g。在评估2.0版Y仉求的q程中,发现一部分发动机是电池驱动的Q而电池需要一定的充电旉。销售部门的人希望能够通过计算机查阅充甉|间。根据这一要求定义一个新的行为,如图1所C?br />
行ؓ2Q查询电驱动发动机的充电旉Q发动机返回一个表C充甉|间的整数?br />
用JavaҎ来描q这个行为,代码如下Q?br />
public abstract BatteryPoweredMotor extends Motor{
abstract public int getTimeToRecharge();
}
在销售部门的软g中,电驱动发动机也以cȝ形式实现Q但q些cMBatteryPoweredMotor而不是Motorz。这些改动加入到2.0版Y件之后,销售部门很满意。随着业务的不断发展,不久之后光驱动的发动机出C。销售部门要求光驱动发动机需要一定光能才能运转,光能以流明(LumenQ度量。这个信息对客户很重要,因ؓ下雨或多云的天气里,某些光驱动发动机可能无法q{。销售部门要求ؓ软g增加对光驱动发动机的支持Q所以要定义一个新的行为?br />
行ؓ3Q查询光驱动发动够正常运转所需要的最流明数Q发动机q回一个整数?br />
再定义一个抽象类q把行ؓ3转换成JavaҎQ代码如下:
public abstract SolarPoweredMotor extends Motor{
abstract public int getLumensToOperate();
}
如图1所C,SolarPoweredMotor和BatteryPoweredMotor都从Motor抽象cL生。在整个软g中,90Q以上的代码以相同的方式对待所有的发动机。偶需要检查一下发动机是光驱动q是电驱动,使用instanceof实现Q代码如下:
[color=#336600]
if (instanceof SolarPoweredMotor){...}
if (instanceof BatteryPoweredMotor){...}
无论是哪U发动机Q马力这个参数都很重要,所以在所有派生的抽象c(SolarPoweredMotor和BatteryPoweredMotorQ中QgetHorsepower()Ҏ都有效?br />
现在销售部门又有了一U新的发动机Q它是一U既有电驱动又有光驱动的双重驱动发动机。光驱动和电驱动的行为本w没有变化,但新的发动机同时支持两种行ؓ。在考虑如何定义新型的光电驱动发动机Ӟ接口和抽象类的差别开始显C出来了。新的目标是在增加新型发动机的前提下量改动代码。因Z光驱动发动机、电驱动发动机有关的代码已经q全面的试Q不存在已知的Bug。ؓ了增加光电驱动发动机Q要定义一个新的SolarBatteryPowered抽象cR如果让SolarBatteryPowered从Motor抽象cL生,SolarBatteryPowered不支持针对光驱动发动机和电驱动发动机的instanceof操作。也是_如果查询一个光电驱动的发动机是光驱动的Q还是电驱动的,得到的答案是Q都不是?br />
如果?SolarBatteryPowered从SolarPoweredMotorQ或BatteryPoweredMotorQ抽象类zQ类似的问题也会出现QSolarBatteryPowered不支持针对BatteryPoweredMotorQ或SolarPoweredMotorQ的 instanceof操作。从行ؓ上看Q光电驱动的发动机必d时从两个抽象cL生,但Java语言不允许多重ѝ之所以会出现q个问题Q根本的原因在于使用抽象cM仅意味着定义特定的行为,而且意味着定义实现的模式。也是_应该定义一个发动机如何获得行ؓ的模型,而不仅仅是声明发动机h某一个行为?br />
通过接口建立行ؓ模型
如果用接口来建立行ؓ模型Q就可以避免隐含地规定实现模式。例如,前面的几个行为改用接口定义如下?br />
行ؓ1Q?br />
public interface Motor(){
public int getHorsepower();
}
行ؓ2Q?br />
public interface BatteryPoweredMotor extends Motor(){
public int getTimeToRecharge();
}
行ؓ3Q?br />
public interface SolarPoweredMotor extends Motor{
abstract public int getLumensToOperate();
}
现在光电驱动的发动机可以描述为:
public DualPoweredMotor implements SolarPoweredMotor, BatteryPoweredMotor{}
DualPoweredMotor只承行为定义,而不是行为的实现模式Q如?所C?br />
在用接口的同时仍旧可以使用抽象c,不过q时抽象cȝ作用是实现行为,而不是定义行为。只要实现行为的c遵从接口定义,即它改变了父抽象类Q也不用改变其它代码与之交互的方式。特别是对于公用的实C码,抽象cL它的优点。抽象类能够保证实现的层ơ关p,避免代码重复。然而,即在用抽象类的场合,也不要忽视通过接口定义行ؓ模型的原则。从实践的角度来看,如果依赖于抽象类来定义行为,往往Dq于复杂的承关p,而通过接口定义行ؓ能够更有效地分离行ؓ与实玎ͼZ码的l护和修改带来方ѝ?img src ="http://www.aygfsteel.com/jsdk999/aggbug/71274.html" width = "1" height = "1" />
]]>
վ֩ģ壺
|
|
|
ɽ|
ͬ|
|
|
ǿ|
|
ľ|
|
|
|
ɽ|
³|
|
|
|
ų|
ij|
|
|
|
ɽ|
Ž|
ƽ|
|
ˮ|
ƺ|
Ѩ|
ˮ|
|
㺺|
ն|
|
|
|
|
|
|
|