首页 > OOP语言 > VB.net > 正文

VB.NET之旅(十)―何时用接口
2012-09-03 00:00:00   来源:www.bianceng.cn   评论:0 点击:

暂时无描述信息

大李没告诉我接口与抽象类的区别,什么时候用接口,什么时候用实现继承。 弄得我中饭也没吃好,老在琢磨这事,这不,一吃完饭,我就冲上楼,一个房间 一个房间转,到处找大李。

过了好一阵,这老哥才和几个同事说说笑笑地 回到办公室,我立即走上前,半请半拉地把他拽到电脑旁。“大李哥,我实 在想得头晕,既然在VB.NET中接口有了这么大的发展空间,在形式上与抽象类如 此相似,那么它们有什么区别?什么时候用接口呢?”

听着我一连 串的问题,大李微笑着摇摇头,拍拍我的肩膀说:“小兄弟,不光是你弄不 清,其实就是很有经验的程序设计师也对什么时候用接口,什么时候用抽象类而 头痛咧。”

此话一出,我更是疑惑重重。不过反而安下心来,老鸟 们都弄不清的问题,我不清楚也不必心中不安了。哈……

大 李看着我忽忧忽喜的表情露出了一丝诧异,不过他没有理会,继续说:“但 是这个问题我们还是有必要好好分析一下,让我们更明白接口与抽象类的具体含 义。”

“我们早说过,抽象类是一种不能实例化而必须从中继 承的类。抽象类可以完全实现,但更常见的是部分实现或者根本不实现,从而封 装继承类的通用功能,它可以提供已实现的成员,因此,可以用抽象类确保特定 数量的相同功能,但不能用接口这样做。”

“接口是完全抽象 的成员集合,它的成员都无法在接口定义时实现,我们可以将它看作是为操作定 义合同,接口的实现完全留给开发者去做。它们之间的区别,如果认真分析,还 是有不少的:在VB.NET中,类只能是从一个基类继承,所以如果要使用抽象类为 一组类提供多态性,这些类必须都是从那个类继承的;接口就不一样了,它不但 可以用一个类或结构实现多个接口,一个接口还可以有多个实现。 ”

“也就是说,它们在提供多态性的问题上是有差别的? ”我好象听懂了点什么。

“这是一个重要的区别,我们也可以 从多态性的角度来考虑是要使用接口还是用抽象类。”大李同意了我的观点 ,“如果预计要创建组件的多个版本,我们应该创建抽象类。这是因为,抽 象类提供简单易行的方法来控制组件版本。通过更新基类,所有继承类都随更改 自动更新。这是好处,当然也是问题,对吧?(详见前文《脆弱的基类》)另一 方面,接口一旦创建就不能更改。如果需要接口的新版本,必须创建一个全新的 接口。所以,如果创建的功能将在大范围的全异对象间使用,则使用接口。 ”

我想了一下,接着大李的话说:“能不能这样说,抽象类主 要用于关系密切的对象,而接口最适合为不相关的类提供通用功能。 ”

大李对我伸出了大拇指:“不错,小伙子悟性很好呀!你想 ,我上午跟你说,要创建控件,首先就是要对一些接口进行实现以让系统能够识 别(详见前文《接口》)。而各个控件之间的联系其实关联性并不大。所以,它 们的基础大都是接口。但是,我们要注意一点,在组件设计时,如果要在组件的 所有实现间提供通用的已实现功能,则使用抽象类。这是因为我们刚才说过的原 因,抽象类允许部分实现类,而接口不包含任何成员的实现。 ”

“唔,明白了,它们之间的区别有点明白了。”我默 默地点了点头。

“另外,有个通用的设计思想,如果要设计小而简 练的功能块,则使用接口。如果要设计大的功能单元,则使用抽象类。”大 李又补充了一条建议。

“看来设计的问题还是蛮大的,一般来说, 怎么设计接口呢?”我接着问。

“为什么你所看到的编程书籍 也好,程序例程也好,极少有对接口的描述,而对类实现继承的例子比比皆是? 这就从一个侧面给我们提了一个醒,如果使用适当,接口可以成为很有用的工具 。但如果使用不当,它们会变得非常棘手,甚至妨碍有效的编程。接口的设计与 使用其实是一项高明的艺术。”大李郑重其事的说。

“艺术? ”我惊叫了一声。

“没错,艺术!”大李又加重了一下 语气,“通过接口与实现的方式,我们可以将同一类型的程序运用在不同的 对象上面,而且不必修改原有类,相对子程序必须通过修改源程序代码才能够达 到重用的目的,接口与实现不仅是伟大的进步,也是境界极高的程序设计艺术。 ”

“哦,这倒是真的。”我回想起今天看到的接口的例 程。

“但是,最大的问题还是集中在接口设计上。”大李接着 说,“接口一旦被定义和接受,就必须保持不变,以保护为使用该接口而编 写的应用程序。接口发布后,就不能对其进行更改。这是我们进行组件设计的一 个重要原则,叫做‘接口不变性’。”

我点了点头: “接口不变性,这个我可以理解了。”

“我已经反反复 复强调过,创建一个接口就是在创建一个定义,接口定义发布后则永远不能更改 。接口不变性,就是为了保护为使用接口而编写的现有系统。当接口设计与需求 有所出入,确认需要大幅度变更时,我们应该创建新的接口。一般命名方式是, 新接口可以通过在原来的接口名称后追加一个数字‘2’来命名,以显 示出它与现有接口的关系。然后通过接口继承来创建新接口。 ”

“可是,如果需求分析得不好,岂不是会出现一大堆的派生 接口了?”我不免有点顾虑。

“这是肯定的,而且过于频繁地 生成新接口,会因未使用的接口实现而使组件变得很庞大。有经验的设计师,在 充分分析需求后,设计出的接口往往很小且相互独立,减少了性能问题发生的可 能。”

“这种分解能力倒真的是艺术呀!”我不禁为之 叹服。

“当然,一般来说,我们会把确定哪些属性和方法属于接口 的设计过程称为‘接口分解’。基本准则是,应在一个接口中将紧密 相关的几个功能聚合为一组。功能太多会使接口不便于运行,而过于细分功能将 导致额外的系统开销并降低使用的简易性。掌握分解的这个度的能力是需要不断 的在技术上进行磨炼,以及在对每个项目深入分析与理解的基础上才能得到的。 ”

“明白了。”我大声地回答着,真希望自己能早一天 成为接口设计大师。

大李笑着拍了拍我:“明白了就好。其实,与 设计接口相比,创建大的实现继承树更容易出错。”

“当然, ”我脑海里浮现起实现继承的各个环节,“这是不是说,在某些时候 适当使用接口还是很有益的。”

“看来你真的明白了,那你再 来说一下,接口与类实现继承相比,好处有什么?”大李回过身开始找茶杯 。

我低下头,努力地转动了一下脑子:“我试着说一下吧,总体而 言,接口是一种非常有效的编程方法,它让对象的定义与实现分离,从而可以在 不破坏现有应用程序的情况下使对象得以完善与进化。接口消除了实现继承的一 个大问题,就是在对设计实施后再对其进行更改时很可能对代码产生破坏。即使 实现继承允许类从基类继承实现,在类首次发布时仍然会使我们不得不为设计做 很多的抉择。如果原有的设想不正确,并非总可以在以后的版本中对代码进行安 全的更改。比如,我们定义了一个基类的方法,它需要一个 Integer 参数,而后 来又确定该参数应该为 Long 数据类型。我们无法安全更改原始类,因为为从原 始类派生的类所设计的应用程序可能无法进行正确编译。这一问题会扩大化,因 为单个基类会影响几百个子类。”

“那用重载原始类并采用一 个Long类型的参数,不就能解决这个问题了吗?”大李提了个问题。

“这个么?”我想了一下,“可是,这样不一定能达到 满意的效果,因为一个派生类可能需要对采用整数的方法进行重写,如果取 Long 数据类型的方法不能被重写,该派生类可能无法正常运行。 ”

“那用接口怎么做?”大李不依不挠地继续问。

“办法就是发布接受新数据类型的更新接口。”我一下子就回 答出来了。

“看来你已经掌握了接口操作的基本环节了。”大 李的评语真让我高兴。“我再帮你总结一下,使用接口继承而不用类继承的 主要原因有:在应用程序要求很多可能不相关的对象类型以提供某种功能的情况 下,用接口适用性会更强;接口比基类更灵活,因为可以定义单个实现来实现多 个接口;在无需从基类继承实现的情况下,接口更好;在无法使用类继承的情况 下接口是很有用的。例如,结构无法从类继承,但它们可以实现接口。 ”

我抿着嘴用力点了点头,同时在心里默默地记忆着大李所说的每 一条准则。

“回去好好想想,多写几个小程序来练习一下,明天我 们还要欣赏VB.NET提供的强大的可视继承的表现呢。”

相关热词搜索:

上一篇:VB.NET之旅(十一)―可视继承
下一篇:VB.NET之旅(九)―接口继承

分享到: 收藏