软件框架设计的艺术

所需积分/C币:10 2017-04-11 13:47:11 63.46MB PDF
8
收藏 收藏
举报

软件框架设计的艺术
TNG圈灵程序设计M书 Practical API Design Confessions of a Java fr ork Architect 软件架设计的艺术 [捷] jaros l av lulach著 王磊朱兴译 人民邮电出版社 北京 最新编程资源分享下载站htp;/www.pin5icom/ 序言:仅仅是又多了一本设计书吗 读者也许会想:“在程序开发领域中,讲述软件设计的技术图书是不是太多了?”,的确如此, 因而你有理由来质疑,为什么我还要写一本这样的书而你又凭什么还要再读这样一本书?说起软 件设计的经典图书,那本由GoF执笔的《设计模式》,对每一个想要掌握面向对象技术的开发人 员来说,已经成为案头必备之书。此外,对于不同类型的应用开发,也存在大量专业的软件设计 模式图书。还有 Efective Java,这本传世之作已经成为众口相传的Java程序开发圣经。基于以上 事实,还有必要再多一本关于软件设计的图书吗? 我相信这自有其必要性。从1997年开始,我一直从事 NetBeans的API设计工作。在此期 间,与其他设计框架或者通用功能库的人一样,我也经历了各种酸甜苦辣。刚开始时,我一边 尝试将其他语言的一些好的代码风格照搬到Java语言上,一边慢慢地找感觉。随后我对Java语 言使用渐趋熟练,将已知的模式应用到我写的Java语言代码上,看起来也就容易多了,当然后 来,我又发现事情远不是想象中的那么简单。我认识到,要设计 NetBeans这样一种面向对象的 应用框架,直接套用传统的模式并不恰当,不管那些传统的模式有多成功,它所需要的是一门 全新的技艺。 NetBeans中最早的API要迫溯到1997年了,距今已有10多年的历史,至今仍然有不少用户 在使用这些API,而且程序运行一切正常,当然坦率地说其中有很多内容与开始时的设计已经不 尽相同。在这10多年中,我们也经常根据新的需求来调整和扩展类库的功能,同时对开始时犯 下的一些错误进行修正。尽管如此,那些使用了这些AP的客户仍然可以使用最新版本的类库来 编译并运行他们早先的程序。这一切并非偶然,因为我们一直在尽最大的努力来保证类库的向后 兼容性。即使客户使用我们10多年前提供的类库来编写程序,然后用最新版本进行编译和运行, 这些程序仍然可以平稳地工作。这种有效地保护客户原有的软件投资的理念非常重要,但在常见 的设计图书中却无法找到,至少在我读过的那些书中无人提及。当然,在 NetBeans平台的开发 过程中,并不是所有的API的演化之路都是一帆风顺的,但我相信, NetBeans的团队成员已经炉 火纯青地掌握了这方面的AP设计技巧,而其他组织的开发人员也同样需要了解这些技巧。基于 这个原因,向后兼容性这个话题在本书中占用了大量篇幅,书中还大量介绍了特殊的AP设计模 式,有助于编写适合向后兼容的代码。 NetBeans团队工作的扩展能力是当时所面临的另外一个挑战。1997年项目刚刚开始的时候, 由我个人负责AP的开发,其他工程师的工作则只是写代码,也就是说他们负责完成用户界面并 2序言:仅仅是又多了一本设计书吗 实现其他 NetBeanS iDE,这些工作都需要频繁用到我所设计的API。毫无疑问,当时我就变成了 整个项目的瓶颈。我开始认识到,实现 NetBeansIDE功能的开发人员越来越多,我一个“架构师” 不可能完成所有的AP需求。随着时间的流逝,急需做出改变。 Net Beans的开发团队中的大部分 开发人员都应该能够设计他们自己的API。而且不管是哪个开发人员设计的API,我们希望保持 一致性。但一致性在这里却成为最大的一个问题,原因不是出在开发人员身上,他们其实也想保 持一致性,只是因为我当时无法给他们解释清楚我所指的一致性到底是什么东西。相信很多人也 有过与我类似的感觉:自己知道如何去做一件事,但就是无法清楚地解释给别人听。我当时就处 于这种状态:我觉得自己知道如何设计AP,但却花了好几个月的时间才整理出想让大家遵守的 最重要的规范。 铭记于心的AP讲座 直以来,我对设计和发布AP都有着浓厚的兴趣。在Sun公司内部以及为 NetBeans合 作伙伴我也做过多次关于该议题的讲座。但直到2005年在旧金山举行 JavaOne会议时,我才 第一次就这个议题进行了公开讲座。当时我和我的朋友 Tim Boudreau向大会提交了一份议题, 名为:如何设计历久弥新的API。也许是因为在议题摘要中没有写上Ajax和Wb20这种吸引 眼球的字样,我们的议题被安排在晚上10点30分。对于讲座而言,这个时间点实在算不上理 想,各种聚会、免费的啤酒宵夜,以及午夜的各种娱乐活动都会抢走我们的听众。我们深受打 击,只能期望讲座期间会有一两个朋友来露上一小脸,问上几个问题。当晚我们抵达会场,看 到隔壁将要进行一场JBC的讲座时,我们的情绪更是一下子跌到了谷底。走廊里挤满了人, 我们以为这些人都是对数据库感兴趣,准备来参加隔壁的JDBC技术讲座的。但让我们吃惊的 是,大部分听众其实是冲着我们的讲座来的!举办讲座的房间很快就水泄不通了,座无虚席, 还有些听众干脆坐在地板上或者侍墙而立,甚至门都不能关上,因为还有部分人只能站在外面 的走戽听。最終,我做了一场从未有过的激动人心的讲座。 自那以后,我确信有很多人想要了解如何设计API,这种需求并非凭空臆造,而是真实存 在的。因此在我摆写此书的过程中,每当快要失去动力的时候,便会想起那场激情澎湃的讲座, 就又重燃热情。这场讲座时刻提醒着我,那些源于实践并指导我们正确设计API的原则应当被 记录下来。这些原则虽然基于大量的设计图书介绍的设计知识,但在本书中得到强调和扩展, 因为API设计有其特殊性。 AP设计的特殊所在 为什么说市场上现有的设计图书还不够用呢?这是因为设计框架或者通用类库是一件非常 复杂的事情,其复杂度与自行设计内部系统不可同日而语。打个比方,在一台服务器上基于一个 小型数据库来搭建一个Web应用之类的小系统,就和盖一间房子差不多。当然,有些房子可能 很小,也有些房子会很大,有时也许是一座摩天大楼。这些建筑通常情况下都只有一个主人,只 有他才会改造这个房子。如果需要的话,改一下屋顶,换上新窗户,也许会砌面墙多隔出一间来, 最新编程资源分享下载站htp;/www.pin5icom/ 序言:仅仅是又多了一本设计书吗3 再拆旧墙打通两个房间,等等。当然,有些改变算不上什么麻烦事,如换个屋顶不会对地板造成 什么大的破坏,换个窗户,只要大小规格不变,也不会影响别的部位。但是,如果想把窗户从小 变大,就不那么简单了,而想换个两倍大的新电梯更是不可能完成的任务。再如,罕有人会疯狂 到盖个新的一楼,然后把原来的楼层都往上移一层。这样做实在是问题多多,弊大于利。当然, 从技术角度来看,上面这些变化仍然是可行的。只要这个房间的主人确有这个需要,铁了心也能 做到。 内部软件系统也有些相似。通常也只有一个所有者,而且它还具有完全的控制权。如果现在 需要对系统中的部分功能进行升级,那么尽管放手去做就是了!如果要改变一下数据库的模式, 也可以悉听尊便。当然,有些改变会比较复杂。拿以下两种情况作个比较:修改一行代码来修复 个№ 17PointerException的bug和调整数据库模式,显然,后者的影响会大得多。但对于内部 系统来说,一切改变都是可行的。因为其所有者有着绝对的控制权,只要系统确实需要大的升级, 甚至可以暂时关闭这个应用系统,等完成升级以后再重新运行。此外,我们已经有了不少相关的 设计原则帮助,我们更好地管控一个内部系统的变化。有设计模式的书籍帮助开发人员更好地组 织代码,还有不少关于设计系统和测试系统的方法论,还有大量的图书介绍如何组织和领导员工 进行团队合作。可以说,维护一个内部系统的方方面面,都是非常清楚明了的,也有很多详细文 档可供参考。 但是编写AI则有所不同。可以拿宇宙来打个比方,尽管宇宙不像先前说的房子那么直观, 但还算得上比较形象。先来回忆一下我们已知的宇宙,我说“已知”的字宙,是因为没有人能洞 悉宇宙的一切,所有那些恒星、银河,以及其他天体,还包括无形的内容,如所有物理规律。当 然,人类现在对宇宙所了解的其实只算得上沧海一粟。我们的视野有多宽,就限定了宇宙在我们 眼中的样子,也就是说,我们所说的宇宙,只是在我们自已眼中的宇宙,是真实字宙在我们眼中 的一个缩影。它包含了无数的天体和状态,然而,我们的经验和想象告诉我们,在我们视野范围 以外,还有其他的星星和银河,但我们对它们一无所知。千百年来,人类通过打造更先进的设备 及不断地认识和理解自然的规律,不停地扩展自己的视野,不断地发现新事物或者新规律,人类 关于宇宙的认识和经验就是基于上述实践而逐渐形成的。 宇宙并非亘古不变,而是时刻都在变化,但其变化却有规律可循。这些规律告诉我们,行星 恒星以及其他天体之间是如何相互影响的。举例来说,假设某个人通过自己的观察,发现了一颗 新的恒星,那么不管明天、后天还是大后天,都可以观察到这颗恒星,这并不奇怪。虽然现有的 自然规律告诉我们:恒星不仅会移动,而且会旋转,甚至还会爆炸。但这些变化都会遵从自然规 律。不会有人隔一两周就发现一件宇宙大事,说有某个恒星出现了,消失了,或者是进行随机性 的移动。如果宇宙真有这么疯狂,那么就完全颠覆了我们今天对于字宙的认识。我们通常认为 一旦一颗恒星被发现,它就会长久存在,甚至相信即使无人观察到它,它依然存在。这颗恒星可 以被地球上的一个人观察到,也可以被太阳系其他地方的另外一个人观察到,甚至还有宇宙中其 他智慧生物观察到,当然也可能无人注意它。但恒星本身并不知道自己是否被他人所观察,它只 会默默遵照自然规律存在和运行。因此一旦被发现,它便一直陪伴着我们。 好的API也是如此。一旦某个通用的类库在某个版本引入了一个新方法,就好像发现了一颗 4序言:仅仅是又多了一本设计书吗 新的恒星。所有使用该类库的人都可以看到并使用该方法。至于是否在自己的程序中使用,则要 视乎程序员自己的需要了。有可能,多数AP的使用者对你添加的新方法完全不在意。但你不能 把希望寄托在这种并无根据的猜测之上。多年的开发经验告诉我,AP的用户太有创意了。有时 候,他们涉及的领域甚至超过了A设计者。换句话说,只要API有可能被误用,就定会有人 去误用这个API。随之而来的结果就是,不管是方法本身还是其设计者,都不知道该方法是否被 使用及其使用频率有多大。也许会有很多用户使用它,也许一个都没有,但除非你想破坏优秀 API的设计法则,即打破其向后兼容性,否则就必须假定有人在观察,必须保证这些AP得到良 好的维护和保留。“AP就如同恒星,一旦出现,便与我们永恒共存。” 宇宙与AP的设计还有一个相似之处。我们对字宙的认识不断加深,正如我们的类库在不断 演进。古希腊人已经可以识别和观察远至土星和木星的所有行星的运行路线,这就是他们眼中的 宇宙的样子。他们尽力去解释行星运行背后的原因,但以今天的标准来看,他们显然并不成功。 他们还不能揭示出行星运行的规律。到了文艺复兴时期,哥白尼提出了日心说,而开普勒则用行 星三大定律来诠释行星相对于太阳的运行轨迹和速度。这些探索丰富了人类对字宙的发现,从而 能够对“宇宙是什么”进行精确的解释。但没有人知道“宇宙为什么是这个样子”。直到1687年, 牛顿才对这个问题给出了诠释,他引人了万有引力的概念。万有引力不仅可以用来解释开普勒定 律,还极大地扩展了我们对宇宙的认识,因为对于已知字宙中多个天体间发生的所有事情,基于 牛顿定律的物理学°几乎都可以给出合理的解释。 一切看来都很完美,直到19世纪末。很多实验都发现了一些无法用牛顿定律来解释的现象, 特别是对于一些高速运动的天体。这些现象促使爱因斯坦创立了相对论,帮助我们更深入地理解 宇宙及其各种现象包括对高速运动的天体的理解。事实上,爱因斯坦的理论是牛顿理论的延伸, 只要天体慢到一个合理的速度,那么使用这两个理论可以得到相同的结果,此时可谓殊途同归。 前文啰哩啰嗉地说了很多物理和历史背景的内容,这些东西与设计AP有半点关系吗?接下 来先让我们来假设有一个上帝,万能的他通过一个AP库与人类进行沟通。这个库是人类通向这 个已知的宇宙的桥梁。古希腊人使用这个库的0.1版本,其功能很简单,只能用来列举不同的行 星以及它们的名字。这个库提供的API显然不够丰富,但对于那时候的人来说,已经足够了。借 助于这个简单的API库,古希腊人已经可以分辨几颗行星。在这个库的使用过程中会有不少人经 常提出新的需求,希望对这个AP库加以改进。当开普勒需要进一步了解行星的运行规律时,就 发现这个库的功能已经不能满足他的需要了。因此,这个万能的上帝就给了他一个升级版本,姑 且称之为1.0版吧。这个版本的库能够为每个行星在某个时间点上提供空间坐标,以确定其位置。 同时1.0版本很好地兼容了01版本,也就是说,原来那些古希腊人所使用的功能仍然可以正常 使用。 只不过,用户从来没有知足的时候,物理学家们亦如是。为了帮助牛顿,那位万能的上帝接 着提供了宇宙20这个重要的版本。该版本不仅描述了太阳和其他行星之间存在的万有引力,还提 供了一堆公式用以计算空间物体的引力、加速度及速度,也不再只局限于行星了。不用说,这个新 版本仍然兼容以前的版本,古希腊人和开普勒使用的那些功能仍然可以在新版本中正常使用。 ①指的是经典物理学。—译者注 最新编程资源分享下载站htp;/www.pin5icom/ 序言:仅仅是又多了一本设计书吗5 至此,所有的变化都很直接。一直以来,那位万能的上帝只是为新版本添加了一些功能。在 经典物理学成熟以后,物理学家声称,字宙的所有规律都已经被物理学家发现了,在物理学的领 域已经没有什么未解之谜了!这个声明真是一个天大的讽刺,上帝抛出了迈克尔逊实验证明了 这个臆断的荒谬,进而导致爱因斯坦提出他的相对论。这时候,物理学家们发现,最新版本的宇 宙API库出现了无法简单向后兼容的问题,因为新的理论指出,以前所有的物理学家,包括牛顿, 都存在少许的错误!尽管出现了如此大的一个变动,但新的AP库仍然可以按向后兼容方式来处 理。那是因为只有以特别高速运动的物体,根据原有方式来计算得到的结果才有可能不正确。而 在牛顿及其先行者的那个时代,受限于技术等原因,是无法对这样高的运动速度进行测量的。因 此,尽管不兼容的问题早就存在,但用以前的测量技术却发现不了,从而也无法证实宇宙API 库的功能发生了改变。 上述这个荒诞的故事旨在说明我们对字宙的认识一直在不停地进步我们编写的API库也同 样如此。或许乐观的人并不认同,但我真的感觉人类永远都无法了解整个字宙的奥秘。当然,我 认为我们对字宙的了解会越来越多。虽然程序员的观点各有不同,但我相信所有已经在使用的 API库都会永无止境,它们会继续演化。对此,我们必须做好准备。我们必须准备好随时改进我 们的API库,就像我们必须准备好随时修正我们对字宙的认识。 与建造一所房子或一个内部的软件系统不同,编写AP库需要开发人员放眼未来,看到今后 潜在的需求。但在我看来,现在人们设计AP的做法往往不是这样。目前市面上的图书也并没有 促使人们这样思考。书中的设计模式大多只能用在特定版本,使用者也只是在特定上下文的环境 中去考虑问题,他们极少参考老的版本,也不太考虑未来的需求,所举的例子以及相关的上下文 都具有很大的片面性。当然并非说这些书全无裨益,在编写通用功能库和框架时还是需要这些技 巧。现在,我们必须停止学习如何来设计内部系统,而要开始学习如何来设计一套AP库。在学 习中一定要坚持一个观点:“API一且发布,便与我们永恒共存。” 读者对象 如果此时你正在书店面对这本书,在买与不买之间犹豫不决,那是因为你无法判断这本书对 你是否有用。老实说,这点我帮不了你,因为我不是你。但我可以告诉你我自己为什么需要这本 书,以及我写作该书的缘由,这样也许可以帮助你决定是否应该购买此书。我在设计 NetBeans 框架的AP时,就像在一片迷茫中寻找光明,总是摸不清方向。最开始,我完全凭直觉,而且认 为写AP是一种艺术。我知道对于艺术来讲,需要创造力,但设计AP,与艺术是不同的范畴。 时间慢慢过去,我从已经完成的工作中汲取经验,逐渐整理出一整套思路和度量标准,借助于这 些可量化的标准,可以将一个普通的AP优化成一个优秀的APL。 ①迈克尔逊干涉仪是1880年美国物理学家迈克尔逊为研究“以太”漂移速度实验设计制造出来的。1887年,他和 美国物理学家莫雷合作进一步用实验结果否定了“以太”的存在,为爱因斯坦建立狭义相对论开辟了道路。由于 发明了精密的光学仪器和借助这些仪器所做的基本度量学研究,迈克尔逊于1907年获得了诺贝尔物理学奖。 一译者注 6序言:仅仅是又多了一本设计书吗 本书介绍了 NetBeans团队中一直以何种标准来评价AP的质量,并清楚地说明我们团队为 什么一直坚持使用这个标准。事实上,这些标准都是我们经过多年的尝试,并从错误中吸取教训, 才最终得到的。地球人都知道,重新发明轮子并不是一个好主意,这是在浪费时间和金钱,所以 对于那些把AP设计更多地看作是一种工程而非艺术的架构师们,我郑重推荐此书。在 NetBeans 的初创阶段,只有我个人来设计API。当时,我们有一个比较极端的观点:“一群代码开发人 员是不可能设计出一个好的API的。”其实对于一个单兵作战设计人员来说,即使没有任何规则 来约束,他所设计的AP也具有一致性。但像 NetBeans这样的一个大团队,是不能只有一个设 计人员的。所以,我的首要任务就是要去寻找一种方式,让更多的人能够设计API,同时还能保 持整体设计上的一致性。那个时候我已经开始撰写本书,希望能告诉大家AP设计方面的相关理 论,以及我们编写API的原因和目标等,同时还根据我们过去的经验总结出一些规则,方便大家 来量化一个API的设计质量。接下来,我将我的经验与 NetBeans团队中的成员分享。从此,我 开始放手让他们也来编写API,在开始和结束阶段花些时间来评审和指导他们的设计。以我的标 准来衡量,可以说这么做很棒。这10年来,他们一直在努力地学习和进步,现在看来,我们设 计的AP具有了相当商的一致性,并满足了我们的大部分需求。如果你也处于相应的职位,需要 评审或者指导他人来设计API,你将发现本书中的建议会对你有所裨益 当我想为AP给出一个定义时,却发现这个定义的范围非常广泛。要知道,不是说只有 个框架或者是通用库才算是APL。即使只是写了一个普通的类,只要有同事使用了这个类,那 么也算是写了一个API。为什么这样说呢?假设你删除了这个类中的一些方法,或者是改变了 这些方法的名称,哪怕是改变了这个类的一些功能,这个类的使用者都会火冒三丈。为共享库 写AP也面临同样的问题。如果你所写的类有多个人使用了,那么你对该类的修改也许会强制 要求所有用户都进行相应调整,这无异于一场噩梦。这种噩梦其实是可以避免的。如果在开始 写代码时,就把一个类当成一个AP来认真对待,你会少许多麻烦。换个角度来说,其实这事 也不难,只需要设计类的时候再小心一些,在调整的时候多多关注它的兼容性,再参考和借鉴 些好的经验,其实都搞得定。如果根据前面所说的这个定义来分析一下,几乎所有的开发人 员都在编写和设计API API的一个本质特性就是它的工作机制。AP的测试是非常重要的,借助于它,可以更加清 楚地说明API的原理。没有合适的测试,就不可能编写一个好的API。本书有几个章节会列出 些测试方式告诉读者如何来有效地测试一个库的公开接口,而且即使是要处理该库的多个版本 也无碍于测试的正常运行。我会详细地说明测试时要注意的各项内容,包括签名°、单元测试和 兼容性工具。所以,对于那些需要检查API兼容性的人来说,本书非常有价值。 最后要说的是,一个得到广泛使用的类库将会是该库作者的财富。如果这个类库能够很好地 满足现有用户的需求,就会吸引更多的用户来使用,财富将会不停地增加。要知道,只有在类库 拥有了大量的用户以后,才能在这个基础上获得经济利益,从而继续开发和维护这个类库。本书 ①所谓的签名就是英文中的 signaure,表示一个类或一个方法的标识,它与序列化等多个方面都有关系,通常来说, 一个类的签名是由其父类及其所有成员,包括字段和方法决定的,一个方法的签名则由参数或返回值确定。 一译者注 最新编程资源分享下载站htp;/www.pin5icom/ 序言:仅仅是又多了一本设计书吗7 会就这一点展开讨论,那些喜欢从商业角度来审视软件开发的人会对这一个话题很感兴趣。 这本书只适用于Java Netbeans是一个使用Jaa语言开发的IDE框架,我的大部分与AP有关的知识都是从这个 项目中学到的。如果由我来回答这个问题:“这本书是否有益于那些非Java的开发?”那么答案 仍然是肯定的。对于如何评价AP设计是否良好,本书给出了很多准则,这些准则同样适用于其 他的编程语言。本书中的一些议题,例如:开发AP的原因,编写具有良好结构的文档的规则和 动机,还有那些关于向后兼容的原则。这些内容都可以适用于多种编程语言,包括C、 FORTRAN Perl, Python和 Haskell 当然,涉及细节的时候,就不得不提到Java语言的具体特性。要知道,Java首先是一种面向 对象的语言。为面向对象的语言设计API的时候,像继承、虚方法和封装这些特性都必须加以考 虑。因此,本书给出的一些原则更适用于一些特定的面向对象语言,如C++、 Python或Java,至 于C或 FORTRAN这些面向过程的语言,虽然不错,但已经有点古老了,不再适用本书中的原则。 Java是一种非常新的面向对象语言,它引入了垃圾收集器。当前,业界已经普遍接受了Java, 说明即使在产品的正式运行环境下,垃圾收集器也是可用的且有益的。但在Java语言出现之前, 业界更倾向那种自行管理内存的传统方式,如C、CH+都是采用这种方式来管理内存,开发人员 需要明确地声明如何去申请和释放内存。当时也有一些语言,像 Smalltalk或Ada,它们使用了 垃圾收集器,但它们都被当作实验品,没有几个软件开发商敢冒着这样大的风险去使用它们来开 发软件。JaVa却从根本上扭转了这个现象。目前,可以说,一个基于内存自动管理系统的语言可 以用来编写高性能的程序。大多数的软件工程师都已经普遍接受了这个观点,而不像以往只会取 笑或者害怕使用这种基于内存自动管理的语言。一个能够自动管理内存的语言,会对你写的API 有所要求。比如说, Java只能通过malc一样的构造函数来分配对象,而不是像C一样,需要 对应地释放API。而且Java中,其内存的释放无须程序员关注。所以本书中给出的一些意见或者 做法更适用于带有垃圾收集器的语言,就是那种与Java相似、支持内存自动管理的语言。 Jav还推广了虚拟机和动态编译技术的使用。Java的静态编译技术会将源代码编译成多个类 文件。在代码真正运行的时候才去部署和连接这些文件。而这些编译好的类文件格式是不依赖于 具体的处理器架构的,而应用程序最终运行于这个架构上。 以上所说的内容通过运行时环境实现,它不仅将分散的类文件连接起来,还将指令转换成 处理器可以识别的指令。从Java诞生之初,这一点就是Java与传统语言的相异之处。大家都知 ① Haskell是一种纯函数式编程语言,它的命名源自美国数学家 Haskel1 ooks Curry,他在数学逻辑方面的工作使得 函数式编程语言有了广泛的基础。 Haskell语言是1990年在编程语言 Miranda的基础上标准化的,并且以λ演算 为基础发展而来。这也是为什么 Haskel语言以希腊字母λ( Lambda)作为自己的标志。—译者注 ②不同的程序语言中,对于虚方法的定义有所不同,最通用的定义是:能够在运用时才确定的方法就可以称为虚方 法,如Java中的非fa非 static方法,又如C++中的 virtual都算是,甚至C语言中的函数指针也可以算作虚方法。 一译者注 ③原文中用的是Link,翻译为连接。一译者注

...展开详情
立即下载 身份认证后 购VIP低至7折
一个资源只可评论一次,评论内容不能少于5个字
您会向同学/朋友/同事推荐我们的CSDN下载吗?
谢谢参与!您的真实评价是我们改进的动力~
  • 分享王者

关注 私信
上传资源赚钱or赚积分
最新推荐
软件框架设计的艺术 10积分/C币 立即下载
1/0