a我考网

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 171|回复: 0

[专业语言] JAVA认证:Java中如何消除实现继续和面向接口编程

[复制链接]
发表于 2012-8-4 12:44:44 | 显示全部楼层 |阅读模式
在慌忙之际理清消弭实现继续和面向接口编程这样两个年夜问题可不是一件等闲的工作,尤其考虑到自身的熟悉水平。率直的说,这又是一篇“炒冷饭”的文章,但这“冷饭”又确实欠好炒。是以,在阅读了这篇文章之后,你可要批判地接管我的不雅概念,尽管我的不雅概念也是来自于别人的不雅概念。
5 k3 L5 D% ]" H; F  继续是面向对象中很主要的概念。假如考虑到Java说话特征,继续分为两种:接口继续和实现继续。这只是手艺层面的问题,即便C++中不存在接口的概念,但它的虚基类现实上也相当于接口。对于OO的初学者来说,他们很但愿自己的轨范中呈现年夜量的继续,因为这样看起来很OO。但滥用继续会带来良多问题,尽管有时辰我们又不得不使用继续解决问题。
4 \# [$ w8 t4 o# ^; w7 J  对比于接口继续,实现继续的问题要更多,它会带来更多的耦合问题。但接口继续也是有问题的,这是继续自己的问题。实现继续的良多问题出于其自身实现上,是以这里重点谈判实现继续的问题。
* |3 a3 W# q. Z- j& M  举个例子。我要实现一个Stack类,我想当然地选择Stack类继续于ArrayList类;此刻又有了新的需求,需要实现一个线程平安的Stack,我又界说了一个ConcurrentStack类继续于Stack并笼盖了Stack中的部门代码。
, i5 b9 D4 E$ ~# [$ V# m  因为Stack继续于ArrayList,Stack不得不合错误外吐露出ArrayList所有的public体例,即便其中的某些体例对它可能是不需要的;甚至更糟的是,可能其中的某些体例能改变Stack的状况,而Stack对这些改变并不知情,这就会造成Stack的逻辑错误。0 p9 ?7 n( S1 _; U! P
  假如我要在ArrayList中添加新的体例,这个体例就有可能在逻辑上破损它的派生类Stack、 ConcurrentStack。是以在基类添加体例时,必需搜检这些改削是否会对派生类发生影响;假如发生影响的话,就不得不合错误派生类做进一步的改削。假如类的继续系统不是一小我完成的,或者是改削别人的代码的情形下,很可能因为继续发生难以觉察的BUG。2 J8 ~8 r9 H4 W! B. M
  问题仍是有的。我们有时会见到这样的基类,它的一些体例只是抛出异常,这意味着假如派生类撑持这个体例就重写它,否则就如父类一样抛出异常剖明其不撑持这个体例的挪用。我们也能见到它的一个变种,父类的体例是抽象的,但不是所有的子类都撑持这个体例,不撑持的体例就以抛出异常的体例剖明立场。这种做法是很不友好和很不平安的,它们只能在运行时被“侥幸捕捉”,而良多漏网的异常体例可能会在某一天倏忽呈现,让人不知所措。) m! W! _/ \  q1 n7 Z% U) Z
  引起膳缦沔问题的很主要的原因即是基类和派生类之间的耦合。往往只是对基类做了小小的改动,却不得不重构它们的所有的派生类,这就是污名昭著的“懦弱的基类”问题。因为类之间的关系是存在的,是以耦合是不成避免的甚至是需要的。但在做OO设计时,当碰着如基类和派生类之间的强耦合关系,我们就要考虑考虑,是否必然需要继续呢?是否会有其他的更优雅的替代方案呢?假如必然要学究的话,你会在良多书中会看到这样的原则:假如两个类之间是IS-A关系,那么就使用继续;假如两个类之间是Has-A的关系,那么就使用委派。良多时辰这条原则是合用的,但IS-A并不能做为使用继续的绝对理由。有时为了消弭耦合带来的问题,使用委派等体例会更好地封装实现细节。继续有时会对外及向下吐露太多的,在GOF的设计模式中,有良多模式的目的就是为了消弭继续。
8 C9 D# P( U) l% S  关于何时采用继续,一个主要的原则是确定体例是否能够共享。好比DAO ,可以精晓用的CRUD 体例定在一个抽象DAO 中,具体的DAO 都派生自这个抽象类。严酷的说,抽象DAO 和派生的DAO 实现并不具有IS -A 关系,我们只是为了避免一再的体例界说和实现而作出了这一手艺上的选择。可以说,使用接口仍是抽象类的原则是,假如多个派生类的体例内容没有配合的处所,就用接口作为抽象;假如 多个派生类 的体例含有配合的处所,就用抽象类作为抽象。当这一原则不合用于接口继续,假如呈现接口继续,就会响应地有实现继续。
) \* P* M" W0 q; X8 ~7 G  此刻说说面向接口编程。在众多的活络体例中,面向接口编程老是被巨匠们一再的强调。面向接口编程,现实上是面向抽象编程,将抽象概念和具体实现相隔离。这一原则使得我们拥有了更高条理的抽象模子,在面临不竭变换的需求时,只要抽象模子做的好,改削代码就要等闲的多。但面向接口编程不意味着非得一个接口对应一个类,过多的不需要的接口也可能带来更多的工作量和维护上的坚苦。* A  J) C& R$ e7 Y9 W$ ~; Z
  对比于继续,OO中多态的概念要更主要。一个接口可以对应多个实现类,对于声明为接口类型的体例参数、类的字段,它们要比实现类更易于扩展、不变,这也是多态的利益。假如我以实现类作为体例参数界说了一个体例void doSomething,但假如率领哪天感受 ArrayList不如LinkedList更好用,我将不得不将体例重构为void doSomething,响应地要在所有挪用此体例的处所改削参数类型体例,这将年夜年夜增添我的改削工作量)。假如率领又感受用list存储数据不如set好的话,我将再一次重构体例,但这一次我变聪了然,我将体例界说为void doSomething,建树对象的体例改为Set set = new HashSet。但这样仍不够,假如率领又要求将set改回list怎么办?所以我应该将体例重构为void doSomething, Collection的抽象水平最高,更易于替代具体的实现类。即便需要List或者Set固有的特征,我也可以做向下类型转换解决问题,尽管这样做并不平安。& ^0 I3 s( {. u! y% g- Y. f7 g
  面向接口编程最主要的价质ё仝于潜匿实现,将抽象的实现细节封装起来而不合错误外开放,封装这对于Java EE 中的分层设计和框架设计尤其主要。但即便在编程时使用了接口,我们也需要将接口和实现对应起来,这就引出若何建树对象的问题。在建树型设计模式中,单例、工场体例、抽象工场等模式都是很好的解决法子。此刻风行的节制反转模式是以声明的体例将抽象与实现毗连起来,这既削减了单调的工场类也更易于单元测试。) p1 z9 d$ ~. |, f/ W
  做个总结吧。尽管我竭力褒贬继续的欠好鼓吹接口的好,但这并不是绝对的。滥用继续、滥用接口城市带来问题。做Java EE开发的良多伴侣埋怨DAO、Service一一个接口一个类的实现体例,尽管它们似乎看起来已成为业界的最佳实践之一。也许解除失踪接口会使轨范更“瘦”一些,但“瘦”并必然就“好”,需要按照项目的具体情形而定。关于继续和接口的最佳实践,列位看官仍是需要自身的经验堆集和总结了。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|Woexam.Com ( 湘ICP备18023104号 )

GMT+8, 2024-5-7 05:08 , Processed in 0.304895 second(s), 21 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表