什么时候用抽象类继承接口,什么时候用接口

后使用快捷导航没有帐号?
只需一步,快速开始
查看: 8407|回复: 23
告诉大家什么时候用接口,什么时候用继承,什么时候用组合。
UID167931在线时间 小时积分5帖子离线17136 天注册时间
新手上路, 积分 5, 距离下一级还需 45 积分
有这么一个帖子
罗里罗嗦讲一大堆,估计新人越看越迷糊,容易走入误区,其实很简单,该用继承和接口只要判断一下就好了
&is a&是不是的关系用继承。继承是强耦合,慎用。
&has a&有没有的关系用组合。高聚合,低耦合是有道理的。
&can do&能不能的关系用接口。接口约束的是行为。
另外了,那个中国女人,外国女人该使用接口例子相当不合适。AS3和JAVA很像,找本《JAVA与模式》看看吧,虽然这本书相当的罗嗦,但是适合OOP初学者。
[[i] 本帖最后由 dkny0371 于
14:26 编辑 ]
UID58592在线时间 小时积分16800帖子离线17136 天注册时间
外國女人不適合學JAVA。
UID145379在线时间 小时积分33341帖子离线17136 天注册时间
看来我是说偏题了........
实际上我不是在解释什么时候用接口,继承和组合,我想解释的是一个我目前没有找到答案的问题:就是接口对于程序编译和运行的作用.因为我以前的理解,实现接口只是个规范,即使不实现接口,把接口文件删除,程序照样可以正常运行,也不会使得编程因为缺少接口而变得麻烦(团队合作的不讨论).
还有,has a和can do很多时候可以相互转化.has the ability to do=can do.而且这个只是对程序里对象含义,关系的反映,对程序的编译和运行没有实质性的意义.
LZ所言的,也一样,没有解释到接口不存在对编译和运行的影响.虽然这个解释适合于初学者,但是没有把接口对编译和运行的实际作用解释出来.我想解释的是接口的实际作用,或者后面我举的两个图例又把主题说偏了......
UID390132在线时间 小时积分28274帖子离线17136 天注册时间
楼主潜水很久了啊,版主和楼主的帖子我都反复看了,都没看懂。
UID145379在线时间 小时积分33341帖子离线17136 天注册时间
楼主的贴子在你参加过团队或者大型,结构比较复杂的Flash程序之后就会明白
而我的贴子在你做过功能完善的涂鸦板一类的程序以后应该也会明白的.
UID138188在线时间 小时积分21099帖子离线17136 天注册时间
HBro 超版的例子用错了而已...
UID167931在线时间 小时积分5帖子离线17136 天注册时间
新手上路, 积分 5, 距离下一级还需 45 积分
没注意,原来那个帖子是超版的,我理解为什么要用接口呢?为了松散耦合!
比如声明接口
& & & & public interface ISayHelloWorld
& & & & & & & & public function sayHellWorld():
& & & & public class SayHelloWorldImpl implements ISayHelloWorld
& & & & & & & & public function sayHellWorld():void
& & & & & & & & {
& & & & & & & & & & & & trace(&Hello World!&);
& & & & & & & & }
& & & & & & & &
如果这样写代码,当然,删除出接口一点问题也没有。
var helloWorld:SayHelloWorldImpl = new SayHelloWorldImpl();
helloWorld.sayHellWorld();
但是还是推荐这样写,这样的话,删除接口肯定是编译不过去了。
var helloWorld:ISayHelloWorld = new SayHelloWorldImpl();
helloWorld.sayHellWorld();
接口是can do的关系,代码依赖的是ISayHelloWorld接口,而不是某种具体实现。地球人,火星人,机器人都可以say helloworld,比如
public class Earthman extends Animal implements ISayHelloWorld
public class Martian extends ExtraterrestrialBeing implements ISayHelloWorld
public class Robot extends Machine implements ISayHelloWorld
当然,我上面的代码还是要修改,写个工厂类就好了。
接口是契约,一旦确立,就不能更改,比如我要扩展ISayHelloWorld接口,我想传一个参数,规定语言,cn就是“你好,世界”,en就是Hello,World,这个时候应该建立一个新的接口叫ISayHelloWorld2,如果你把原来的接口改了,恐怕都编译不过去了。尤其在一个团队里,如果不划分好模块,定义清晰接口,自己只顾写自己的程序,最后集成的时候肯定一大堆问题。当然,如果一个比较小的FLASH项目,几千行代码,面向接口编程的优势是很难体现的,而且还要多写多代码,一大堆工厂类,所以AS 3.0是不是需要JAVA那样严谨的语法我是一直保留的,我觉得FLASH这种东东,原来像JavaScript那样的基于prototype足够好用了,如果把超版的例子用原来弱类型语法的,写起来还能少不少的代码呢,只是一些错误必须运行的时候才能发现。
UID145379在线时间 小时积分33341帖子离线17136 天注册时间
本来还想佩服下LZ的,不会因为我是超版而支持我的观点,现在看来.....
cat哥,不用这么强调一下吧,AS3版块的版主是你也.
如果按照LZ的这个解释,那又回到了我最原始的理解上面去了.......接口只是为编译设一道关卡,以避免运行时才发现错误.........
UID167931在线时间 小时积分5帖子离线17136 天注册时间
新手上路, 积分 5, 距离下一级还需 45 积分
原来超版吃硬不吃软,说的委婉点还不乐意。
接口本来就是编译设的一道关卡,PYTHON就没接口,C++也没接口。
[[i] 本帖最后由 dkny0371 于
09:10 编辑 ]
UID168234在线时间 小时积分81帖子离线17136 天注册时间
初级会员, 积分 81, 距离下一级还需 119 积分
接口是为了解耦,来应对多变的需求。与项目的大小与复杂度无关,只不过小项目如果需求变化了重新写需要的时间与精力要少复杂度也低,所以设计模式在其上面的优势没有体现出来罢了!
OO设计中有一条叫依赖接口而不依赖实现目的也在此,初象的东西往往是相对稳定,相对不容易变化的!初象类与接口存在的目的是相同的,只不同接口是一个纯虚的类罢了。
UID33446在线时间 小时积分8611帖子离线17136 天注册时间
原帖由 [i]dkny0371 于
09:08 发表
原来超版吃硬不吃软,说的委婉点还不乐意。
接口本来就是编译设的一道关卡,PYTHON就没接口,C++也没接口。
接口本身是用来定义类的要实现类功能所用的;
接口在多人合作的情况下,它的作用可以体现出来了!
UID145379在线时间 小时积分33341帖子离线17136 天注册时间
原帖由 [i]dkny0371 于
09:08 发表
原来超版吃硬不吃软,说的委婉点还不乐意。
接口本来就是编译设的一道关卡,PYTHON就没接口,C++也没接口。
也不是这样,只是你态度的一个改变让我觉得有点别扭而已.呵呵.
至于kinglong大虾的话......似乎又是回到我原始的理解中去.
顺便感谢kinglong的CS3组件教程,没有你这个教程,我估计我搞大半天都编译不到那些AS3组件.
UID168234在线时间 小时积分81帖子离线17136 天注册时间
初级会员, 积分 81, 距离下一级还需 119 积分
虽然我对设计模式的研究不是很透彻,但是感觉在这里谈模式是浪费表情!
搞AS的人始终不能站的更高的高度看问题,理解问题,解决问题.
UID145379在线时间 小时积分33341帖子离线17136 天注册时间
.....其实这个模式的讨论不是我引起的,我没有谈模式的意思,不过既然有人谈了,我也阻止不来.不过LS的话让我感觉到自己好失败.走人.
UID138188在线时间 小时积分21099帖子离线17136 天注册时间
原帖由 [i]jubupx 于
10:27 PM 发表
虽然我对设计模式的研究不是很透彻,但是感觉在这里谈模式是浪费表情!
搞AS的人始终不能站的更高的高度看问题,理解问题,解决问题.
虽然大多数做 as 的都是半路出家, 他们对 OO, 设计模式, 解藕可以说是几乎没有接触过
这不能怪他们, 因为 as 一开始就是脚本语言, 而且用 as2 写 OO 实在是蹩脚, 加上大多数功能根本不需要使用 OO
现在有了 as3, 有不少做 c#, java, 甚至 c++ 转到 as 来, 越来越多的传统程序员加入了前端开发的行列中
所以不能一概而论
原帖由 [i]kinglong 于
05:35 PM 发表
接口本身是用来定义类的要实现类功能所用的;
接口在多人合作的情况下,它的作用可以体现出来了!
我的理解, 接口只是为了折中的实现多重继承和表达些语义而存在的
多人合作的话, 用抽象类未尝不可?
[[i] 本帖最后由 mirycat 于
23:45 编辑 ]
UID145379在线时间 小时积分33341帖子离线17136 天注册时间
LS的LS似乎没有怪搞AS的人,只是为了说明,搞AS的人大多没有面向对象的编程基础.
我个人始终偏向于mirycat的观点.AS和Java由于无法直接实现多重继承,接口才得以诞生.
有一本Java入门的书就是这么说的.因为多重继承尽管强大,但是编程的难度将呈几何级数上升,而Java的开发者希望这门语言可以比较简单,比较好上手.所以不允许多重继承,但是可以通过接口这一特殊类来模拟多重继承(接口叫特殊类,这一观点似乎要结合抽象类才好理解)
如果可以多重继承,我觉得单用抽象类就已经足够了.
UID58592在线时间 小时积分16800帖子离线17136 天注册时间
哇哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈!!版主到齊了。。。。。
那我說一句很簡單的總結,你可以認為接口就是一個商標,貼上你的商標的對象比如
“宇宙超級無敵產品”的商標貼上去,這個接口可以沒有任何方法,卻可以用于標記和分類。
UID167931在线时间 小时积分5帖子离线17136 天注册时间
新手上路, 积分 5, 距离下一级还需 45 积分
哈哈,潜水了两年多了,发个贴版主都出现,继续潜水
UID167931在线时间 小时积分5帖子离线17136 天注册时间
新手上路, 积分 5, 距离下一级还需 45 积分
另外AS的类库处处体现着设计模式,懂设计模式,对开发AS也是很有好处的。
最后补充一句,不站在DDD(领域驱动设计)的高度看OOP,讨论语言的区别都是扯淡。
UID388051在线时间 小时积分1278帖子离线17136 天注册时间
银牌会员, 积分 1278, 距离下一级还需 1722 积分
回复 #19 dkny0371 的帖子
LZ毕竟是学JAVA过来的..说得都好深奥,什么设计模式,什么面向接口编程,什么驱动设计,题外话,楼主一定是高手..,但是楼主似乎是带着JAVA里面的思想来讨论AS3.0里面的语法问题...,有点像是病人找对了,但是下错药了.....
UID145379在线时间 小时积分33341帖子离线17136 天注册时间
.........LZ太强了.........
还差个火山版主不在
UID138188在线时间 小时积分21099帖子离线17136 天注册时间
原帖由 [i]dkny0371 于
10:04 AM 发表
另外AS的类库处处体现着设计模式,懂设计模式,对开发AS也是很有好处的。
最后补充一句,不站在DDD(领域驱动设计)的高度看OOP,讨论语言的区别都是扯淡。
最后补充一句,不站在DDD(领域驱动设计)的高度看OOP,讨论语言的区别都是扯淡。
DDD? 国内长途直拨电话, 开玩笑
哪有讨论语言的区别
UID247901在线时间 小时积分2788帖子离线17136 天注册时间
银牌会员, 积分 2788, 距离下一级还需 212 积分
as3版块有史以来最强阵容集合帖 留名
我觉得as3出来的话,这里应该多讨论下设计模式、OOP之类的
传统的程序员加入as行列对以前的as程序员是个挑战
UID145379在线时间 小时积分33341帖子离线17136 天注册时间
同意LS的,我既然当初选择了加入AS3的行列,就要接受OOP,设计模式里面的思想.
Powered by什么时候用接口?什么时候用抽象类?
接口相对于抽象类和实体类的好处.
instance )..
抽象类相对于接口的好处
,abstract,.,,.
抽象类和接口相对于实体类的好处.
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。接口和抽象类什么时候使用才合适? -
- ITeye技术网站
博客分类:
理解抽象类
abstract class和interface在Java语言中都是用来进行抽象类(本文 中的抽象类并非从abstract class翻译而来,它表示的是一个抽象体,而abstract class为Java语言中用于定义抽象类的一种方法, 请读者注意区分)定义的,那么什么是抽象类,使用抽象类能为我们带来什么好处呢?
在面向对象的概念中,我们知道所有的对象都是通过类来描绘的,但是反过来却不是这样。并不是 所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。抽象类往往用来表征我们在对问题领域进行分析、 设计中得出的抽象概念,是对一系列看上去不同,但是本质上相同的具体概念的抽象。比如:如果我们进行一个图形编辑软件的开发,就会发现问题领域存在着圆、 三角形这样一些具体概念,它们是不同的,但是它们又都属于形状这样一个概念,形状这个概念在问题领域是不存在的,它就是一个抽象概念。正是因为抽象的概念 在问题领域没有对应的具体概念,所以用以表征抽象概念的抽象类是不能够实例化的。
在面向对象领域,抽象类主要用来进行类型隐藏。 我们可以构造出一个固定的一组行为的抽象描 述,但是这组行为却能够有任意个可能的具体实现方式。这个抽象描述就是抽象类,而这一组任意个可能的具体实现则表现为所有可能的派生类。模块可以操作一个 抽象体。由于模块依赖于一个固定的抽象体,因此它可以是不允许修改的;同时,通过从这个抽象体派生,也可扩展此模块的行为功能。熟悉OCP的读者一定知 道,为了能够实现面向对象设计的一个最核心的原则OCP(Open-Closed Principle),抽象类是其中的关键所在。
从语法定义层面看abstract class 和 interface
在语法层面,Java语言对于abstract class和interface给出了不同的定义方式,下面以定义一个名为Demo的抽象类为例来说明这种不同。
使用abstract class的方式定义Demo抽象类的方式如下:abstract class Demo{abstract void method1(); abstract void method2(); …}
使用interface的方式定义Demo抽象类的方式如下:interface Demo{void method1(); void method2(); …}
在abstract class方式中,Demo可以有自己的数据成员,也可以有非 abstract的成员方法,而在interface方式的实现中,Demo只能够有静态的不能被修改的数据成员(也就是必须是static final 的,不过在interface中一般不定义数据成员),所有的成员方法都是abstract的。从某种意义上说,interface是一种特殊形式的 abstract class。
从编程的角度来看,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间进行选择时要非常的小心。
从设计理念层面看 abstract class 和 interface
上面主要从语法定义和编程的角度论述了abstract class和interface的区 别,这些层面的区别是比较低层次的、非本质的。本小节将从另一个层面:abstract class和interface所反映出的设计理念,来分析一下二者的区别。作者认为,从这个层面进行分析才能理解二者概念的本质所在。
前面已经提到过,abstract class在Java语言中体现了一种继承关系,要想使得 继承关系合理,父类和派生类之间必须存在"is-a"关系,即父类和派生类在概念本质上应该是相同的。对于interface来说则不然,并不要求interface的实现者和interface定义在概念本质上是一致的, 仅仅是实现了interface定义的契约而已。为了使论述便于理解,下面将通过一个简单的实例进行说明。
考虑这样一个例子,假设在我们的问题领域中有一个关于Door的抽象概念,该Door具有执行两个动作open和close,此时我们可以通过abstract class或者interface来定义一个表示该抽象概念的类型,定义方式分别如下所示:
使用abstract class方式定义Door:abstract class Door{abstract void open(); abstract void close();}
使用interface方式定义Door:interface Door{void open(); void close(); }
其他具体的Door类型可以extends使用abstract class方式定义的Door或者implements使用interface方式定义的Door。看起来好像使用abstract class和interface没有大的区别。
如果现在要求Door还要具有报警的功能。我们该如何设计针对该例子的类结构呢(在本例中, 主要是为了展示 abstract class 和interface 反映在设计理念上的区别,其他方面无关的问题都做了简化或者忽略)?下面将罗列出可能的解 决方案,并从设计理念层面对这些不同的方案进行分析。
解决方案一:
简单的在Door的定义中增加一个alarm方法,如下:abstract class Door{abstract void open(); abstract void close();abstract void alarm(); }
或者interface Door{void open(); void close(); void alarm(); }
那么具有报警功能的AlarmDoor的定义方式如下:class AlarmDoor extends Door{void open(){…}void close(){…}void alarm(){…}}
或者class AlarmDoor implements Door{void open(){…}void close(){…}void alarm(){…}}
这种方法违反了面向对象设计中的一个核心原则 ISP (Interface Segregation Principle),在Door的定义中把Door概念本身固有的行为方法和另外一个概念"报警器"的行为方 法混在了一起。这样引起的一个问题是那些仅仅依赖于Door这个概念的模块会因为"报警器"这个概念的改变(比如:修改alarm方法的参数)而改变,反 之依然。
解决方案二:
既然open、close和alarm属于两个不同的概念,根据ISP原则应该把它们分别定 义在代表这两个概念的抽象类中。定义方式有:这两个概念都使用 abstract class 方式定义;两个概念都使用interface方式定义;一个概念 使用 abstract class 方式定义,另一个概念使用interface方式定义。
显然,由于Java语言不支持多重继承,所以两个概念都使用abstract class方式定义是不可行的。后面两种方式都是可行的,但是对于它们的选择却反映出对于问题领域中的概念本质的理解、对于设计意图的反映是否正确、合理。我们一一来分析、说明。
如果两个概念都使用interface方式来定义,那么就反映出两个问题:1、我们可能没有 理解清楚问题领域,AlarmDoor在概念本质上到底是Door还是报警器?2、如果我们对于问题领域的理解没有问题,比如:我们通过对于问题领域的分 析发现AlarmDoor在概念本质上和Door是一致的,那么我们在实现时就没有能够正确的揭示我们的设计意图,因为在这两个概念的定义上(均使用 interface方式定义)反映不出上述含义。
如果我们对于问题领域的理解是:AlarmDoor在概念本质上是Door,同时它有具有报 警的功能。我们该如何来设计、实现来明确的反映出我们的意思呢?前面已经说过,abstract class在Java语言中表示一种继承关系,而继承关系 在本质上是"is-a"关系。所以对于Door这个概念,我们应该使用abstarct class方式来定义。另外,AlarmDoor又具有报警功能,说 明它又能够完成报警概念中定义的行为,所以报警概念可以通过interface方式定义。如下所示:abstract class Door{abstract void open(); abstract void close();}interface Alarm{void alarm(); }class Alarm Door extends Door implements Alarm{void open(){…}void close(){…}void alarm(){…}}
这种实现方式基本上能够明确的反映出我们对于问题领域的理解,正确的揭示我们的设计意图。其 实abstract class表示的是"is-a"关系,interface表示的是"like-a"关系,大家在选择时可以作为一个依据,当然这是建立在对问题领域的理解上的,比如:如果我们认为AlarmDoor在概念本质上是报警器,同时又具有Door的功能,那么上述的定义方式就要反过来了。
1.abstract class 在 Java 语言中表示的是一种继承关系,一个类只能使用一次继承关系。但是,一个类却可以实现多个interface。
2.在abstract class 中可以有自己的数据成员,也可以有非abstarct的成员方法,而在interface中,只能够有静态的不能被修改的数据成员(也就是必须是static final的,不过在 interface中一般不定义数据成员),所有的成员方法都是abstract的。
3.abstract class和interface所反映出的设计理念不同。其实abstract class表示的是"is-a"关系,interface表示的是"like-a"关系。
4.实现抽象类和接口的类必须实现其中的所有方法。抽象类中可以有非抽象方法。接口中则不能有实现方法。
5.接口中定义的变量默认是public static final 型,且必须给其初值,所以实现类中不能重新定义,也不能改变其值。
6.抽象类中的变量默认是 friendly 型,其值可以在子类中重新定义,也可以重新赋值。
7.接口中的方法默认都是 public,abstract 类型的。
jackleechina
浏览: 198499 次
来自: 上海
高质量文章
高质量文章
这里也有一篇文章,分析的更深刻一点:《Math.floor,M ...
还是会出bug,加减乘除都会有精度问题,根本的办法是重写toF ...public abstract class Alternator {
abstract int getPower();//返回功率
…………& 一段时间过后,客户想要开发一套太阳能发电机,因为成本低且环保。太阳照射在电池板上的热量便成了发电厂关心的数据。于是,发电机必须返回表一个示热量的整型数Java code
public abstract class Alternator {
abstract int getPower();//返回功率
在这个抽象类的基础上构造出了煤炭发电机。 &…………& 一段时间过后,客户想要开发一套太阳能发电机,因为成本低且环保。太阳照射在电池板上的热量便成了发电厂关心的数据。于是,发电机必须返回表一个示热量的整型数Java code
public abstract class SunAlternator extends Alternator
abstract int getSunPower();//返回太阳照射热量
………… &又过了一段时间后,客户发现当地经常刮大风,而且风力不小,于是客户想开发一套风力发电机,风速便成了客户关心的数据。于是,发电机必须返回一个表示风速的整数Java code
public abstract class WindAlternator extends Alternator
abstract int getWindSpeed();//风速
这时,对于这些发电机,发电厂偶尔需要检查一下是太阳能发电还是风力发电,代码如下: &if (instanceof SunAlternator){...} &if (instanceof WindAlternator){...} &无论什么发电机,功率这个参数很重要。所以在所有具体类中,getPower()方法都有效。 &随着业务的发展,客户想把太阳能和风力结合起来。太阳能发电和风力发电本身行为没有任何变化,但新型的发电机同时支持两种行为。在考虑如何定义新型的发电机时,抽象类和接口的差别开始显示出来了。软件设计原则之一是:以修改最少的代码来应对需求。太阳能发电和风力发电已经过严格的测试,不存在已知的bug。为了开发新型发电机,就需要定义一个SunWindAlternator,如果让SunWindAlternator从抽象类Alternator派生,那么SunWindAlternator将不支持针对太阳能发电和风力发电的instanceof操作,也就是说,当需要检查发电机目前正在以太阳能形式发电还是以风力形式发电,那么得到的答案永远是:都不是。如果让SunWindAlternator从SunAlternator派生,那么得到的答案永远都是:太阳能发电机;从WindAlternator派生也会遇到类似的问题。------解决方案--------------------这个问题比较严重,呵。。。。
------解决方案--------------------java里面接口是可以多重继承的。我觉得接口更应该是表示 is a 的概念。而抽象类则是is a的一个实现,只是这个实现还不完整,不能单独使用。LZ说的这些情况应该抽象成为接口,这样,比如这个发电机即使风力发电,又是太阳能发电机的时候,那么他们就都是。

我要回帖

更多关于 什么是接口和抽象类 的文章

 

随机推荐