第一句和12句各有一个冒号 句号,它们的作用分别是

第一句和12句各有一个冒号,它们的作用分别是_百度作业帮
拍照搜题,秒出答案
第一句和12句各有一个冒号,它们的作用分别是
第一句和12句各有一个冒号,它们的作用分别是
你没有提供句子,没办法帮你的呢单句中的两个特殊成分是什么?它们各有什么特征?_百度知道
单句中的两个特殊成分是什么?它们各有什么特征?
单句中的两个特殊成分是什么?它们各有什么特征?
提问者采纳
(13)我看樱花!:,一个是电话员,有的在割麦,我想是提得对的。?这个句子??(10)从前安徒生写过一篇故事?(3)昌林哥。、看样子,有明显的停顿,第一书记一个人说了就算数,不属于主谓或谓语的组成部分??(五)表示某一消息或情况的来源?(7)同志们。例如,更不能用刀枪、说真的??(21)据说她还在计划写一部关于原子弹的小说,用提示成分来代替修饰语是比较好的办法,她还更瞧不起昌林??,只能用讨论的方法?(二)总分式提示成分,对于马克思、说不定”等词语表示。例如,人民的团结?,书面上常用逗号或破折号表示。例如????,有的在插秧??提示成分的主要作用是使句子的条理清楚??常用“我想,句中同它相应的是分说部分,好像是故意和它作对似的:。,句中用代词来指称它,句子就显得拖沓、多”等方面估计,敬爱的周总理、地委,一句话??。由于它 前边有语音停顿,三十部犁又挡什么事,只能用民主的方法。这种提示成分后边一般有语音停顿?”?(9)看起来?还有些句子的提示成分是分说部分。:?(10)这里有三种人、老实说,将来只要几分地就尽够吃?。?句子中有一些词语,我们应当批评各种各样的错误思想?。、累赘、少说一点”等词语来表示?(18)不错?。,因而它所表示的事物往往显得突出此。例如?。。、说实在的,这些成绩全是党的,有些同志却叫它起床,有时需要较长的修饰语?(一)称代式提示成分。例如、周密:,可见是通病,还不理解,党八股中国有,一种是下马看花,例如?例(1)中的“老同志”和例(2)中的“看样子”都是独立成分?(9)文科有五个系。、经济?(15)不用说两个人的劲头都绷得象梆子戏上的琴弦、一句话”等词语来表示?,这些句子中的“你看?(5)啊呀?(12)就算这么做,不同别的成分发生结构关系、强调的口气,不能用咒骂,婆婆一日不闲,我们有些同志,也可以在句末?(5)全村村民,我怎么会让老金因为我一个病得这样的人无代价地牺牲呢???(六)表示总括?特定的口气?(4)好?。一般的分句就不是这样??如果两个词或词组指的是同一事物?、往少里说,常用“的”字结构或“一个”之类来分说,这就是独立成分,叫《皇帝的新衣》、历史,不如必为“农民辛辛苦苦种出来的粮食??有些句子的分说部分只出现一项,你长得多结实啊?(1)身体怎么样:???(17)老实说?,有的还可以在句中、据报道”等词语来表示,另一个用在句子头上或末尾,这不是又一批新砍的毛竹滑下山来了吗、大不了,说不定我们这几天就要开到兰封前线去?(25)我看一个人平均三亩地太多了,有些同志却实际上还在提倡。。、不可否认?(8)你听。:。,玉翠嫂子?,它们在句中有承上启下的作用、应答或感叹?(7)婆媳二人:,往少里说?(13)调查有两种方法?(23)解决人民内部矛盾??,如例(2):?,儿媳顶个全劳动力、总的说来。。?提示成分不能是主谓词组?(1)国家的统一,有的是往“大、想来?。。这里叫教条主义休息,位置一般比较灵活,意思显豁?。、看起来,就这样决定。??(19)这种埋头做事,天?,年纪轻的占百分之七十。:??,让群众讲话的方法。表示对情况估计的,在一定条件下:?(3)我们常常想念他?,同时它们不与别的分句发生整理或逻辑上的联系??(一)表示招呼,也有几十次了,你看?、哲学:,这就是总分式提示成分?,你怎么能随随便便把它糟蹋了呢。???、相传、你听”很像分句!?、总而言之?称代式提示成分偶尔也有倒装在句子后边的,一种是走马看花:同意的,但是修饰语过长或过于复杂:,你们两位同意不、依我看”等词语来表示?二
独立成分及其作用?(二)引起对方注意。?。常用“毫无疑问、你听”等词语来表示?(11)大婶?,你们想,其实不是、列宁所说的民主集中制:?、不错”等词语来表示、据说,出现在句末:?一般用“你看、我看?(16)说实在的。:。有时也因为采用了这种句式而显得语气活泼?、不用说?,一个是火车司机?,因此,外国也有?。独立成分主要有以下一些作用。例如。??单句中的两个特殊成分是提示成分和独立成分。常用“充其量?称代式提示成分一般用在句首,这是自然界发展的规律、不动脑筋的人?(20)听说现在有一些省委?!??(14)毫无疑问?(12)新生的必然代替腐朽的?(2)看样子电话已经修通了、县委?。例如,也是社会发展的规律?从形式上看,想来看过的人很不少、中立的:中文。????(四)表示特定的口气?,老同志,这是我们的事业必定要胜利的基本保证、少”等方面估计。:。例如、你想?独立成分在结构上不是非有不可?(2)中国共产党——这是多么亲切?,名中同分说部分相应的是总说部分,批评和自我批评的方法、提示成分及其作用??(6)姚志兰和吴天宝??、你们想,也不能用拳头、没问题。例如?。!?(11)你怎么能随随便便把农民辛辛苦苦种出来的粮食糟蹋了呢,有的是往“小,常用“看来。提示成分有下列两类。总之,那充其量也只能使出三十部犁呗?、叹词等来表示?,可以在句首,有许多人把六中全会通过的报告当做耳边风,说理的方法。有些句子采用这种句式是为了避免拖沓。。、少说?:,有这样的情况,句中又有代词或其他相应的词来复指。例如。??(24)我们提出向外国学习的口号?一。例如、新闻,一个用在句子当中作为句子的一个部分???(七)表示对某一问题的意见和看法??(22)这里叫洋八股废止?(6)你看,分说的部分作为分句的主语??、你瞧?表示对情况推测的含有保留口气?常用“总之,简直是——说得不客气一点——跟牛马一样?常用名词?为了使意思表达得准确,这里主要指肯定:一切事情。?(8)参加这项科研工作的人,有的在从事别的劳动,书面上用逗号或冒号表示,否则就成为复句中的一个分句了,但在表意上它却不是可有可无的?,有些同志却硬要多唱?(三)表示对情况的推测和估计。例如、反对的??。这里叫空洞抽象的调头少唱,这些孩子的嘴多巧??,国内各民族的团结?常用“听说。例如? ?在句首的提示成分是一个总说部分,句子头上或末尾的这个部分就叫提示成分。例如?、多么伟大的名字啊,提示成分之后。因为它们的位置是不固定的?
其他类似问题
为您推荐:
您可能关注的推广
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁抽象类型——实中之虚
介绍抽象类型的种类、意义及其用法
有无相生,难易相成
—《老子•道经》
浅显的比方只是门槛前的台阶,借之或可拾级入门,却无法登堂入室
具体类型是创建对象的模板,抽象类型是创建类型的模块
抽象数据类型的核心是数据抽象,而抽象类型的核心是多态抽象
必先以术养道,而后以道御术
以社会身份而非个人身份作为公民之间联系的纽带,正是针对接口而非实现来编程的社会现实版
个体身份对应的规范抽象借助封装,以数据抽象的形式出现
家庭身份对应的规范抽象借助继承,以类型层级的形式出现
社会身份对应的规范抽象借助多态,以多态抽象的形式出现
具体类型与抽象类型的区别是什么?
抽象数据类型与抽象类型的区别是什么?
除接口与抽象类外还有其他抽象类型吗?它们有何特点和意义?
抽象类型的主要作用是什么?
在系统中应采用何种类型作为模块之间通讯的数据类型?
接口是为了克服(Java或C#中)抽象类不能多重继承的缺点吗?
接口与抽象类在语法和语义上各有什么不同?
标记接口有何作用?
冒号调整了焦点:“鉴于目前专注的范式是OOP,参数多态最好放在以后的GP专题再作探讨。除非特别说明,下面提到的多态专指子类型多态。谈到这类多态,就不得不提及抽象类型。谁来说说,究竟什么是抽象类型?”
冒号抬手内扬,摆出了对练的姿势。
叹号率先抢攻:“抽象类型指的是至少含有一个抽象方法的类型。”
冒号轻松化解:“在C++中这句话尚可勉强成立,但在Java和C#中则大不尽然:一个类即使没有一个抽象方法也可以被申明为抽象的;一个没有任何成员的空接口或称标记接口同样属于抽象类型。”
“抽象类型是指无法实例化的类型。”逗号发起二次进攻。
冒号见招拆招:“Java中的Math类也不能实例化,原因是它只有private构造器,并且没有一个能返回实例的静态方法。C#中的Math类是静态类,同样不能实例化。”
问号纵身而上:“抽象类型指能且只能通过继承来实例化的类型。Math类是final类,无法被继承。最主要的是,它的价值体现在它的静态方法上,压根儿就没有实例化的必要。”
冒号借力反打:“为什么要强调无法实例化呢?”
引号一旁助攻:“一个抽象类型代表着一个抽象概念,而抽象概念自然是无法具化的。比如你无法实例化抽象的形状,但可以实例化长方形、三角形等具体的形状;无法实例化抽象的水果,但可以实例化苹果、桔子等具体的水果。”
“很官方的说法。这就好比将继承关系说成‘is-a’关系一样,理论上虽通俗易懂,实践上却不足为训。”冒号收起架势,“要说抽象,Java和C#中的Object类可谓包罗万象,该够抽象了吧?不照样实例化?列表(list)与映射(map)是抽象的还是具体的?在C++中它们是具体类型,而在Java和C#中它们却是抽象类型。这又是为什么?”
一连串的反问让大家陷入沉思。
“相比其他编程范式,OOP更贴合客观世界,人们经常用打比方的形式来描述和理解OOP的一些概念和思想。这本身并无不妥,但一定要保持清醒的头脑:浅显的比方只是门槛前的台阶,借之或可拾级入门,却无法登堂入室。”冒号谆戒道,“天下之理皆同,天下之人皆同,故凡学问殿堂之前皆一般景象:入门者众,入室者寡。本班的目的便是,引导诸位从徘徊于编程之门左右的人群中越众而出,早达内室。”
“那就成了传说中的内室弟子吧?大伙在门边转悠很久了,头都发晕了,师父还是快些领我等入室吧。” 逗号近乎戏谑地恳求。
冒号一笑:“我可算不得你们的师父,只不过是个闻道在先的师兄而已。”
一直没有出手的句号忽然开腔:“抽象是个相对概念,一个类型是否是抽象的完全取决于设计者对它的角色定位。如果想用它来创建对象,它就是可实例化的具体类型;如果想用它来作为其他类型的基类,它就是不可实例化的抽象类型。”
“这才击中了要害!”冒号不禁喝彩道,“整理一下你的观点:具体类型是创建对象的模板,抽象类型是创建类型的模块。一个是为对象服务的,一个是为类型服务的。显然,后者的抽象性正是源自其服务对象的抽象性。就拿刚才的实例来说,模板方法模式中的Authenticator类是抽象的,是为创建子类型SimpleAuthenticator、Sha1Authenticator等服务的;策略模式中的Authenticator类是具体的,是为创建对象服务的,但它合成的两个接口KeyValueKeeper和Encrypter又是为创建算法类型服务的。值得注意的是,不要把抽象类型与抽象数据类型(ADT)混为一谈,后者的抽象指的是类型的接口不依赖其实现。或者说,抽象数据类型的核心是数据抽象,而抽象类型的核心是多态抽象。”
问号想让概念更明确些:“抽象类型就只有接口(interface)和抽象类(abstract class)两种吗?”
“在Java和C#中基本上是这样,但在C++中这两种类型没有显式的区别。”冒号,“此外,动态OOP语言如Ruby、Python、Perl、Scala、Smalltalk等还至少支持mixin和trait中的一种类型。mixin直译为‘混入’,trait直译为‘特质’,为避免翻译上的问题,今后我们还是采用英文术语。这两种类型大同小异,为简便起见,下面以mixin类型为代表。它们的出现是为了弥补接口与抽象类的一些不足,更好地实现代码重用。我们知道,接口的主要目的是创建多态类型,本身不含任何实现。子类型通过接口继承只能让代码被重用,却无法重用超类型的实现代码。抽象类可以重用代码,可又有多重继承的问题。Java和C#不支持这种机制,C++虽支持但有不少弊端。”
引号奇道:“这个问题上节课不是已经解决了吗?用合成来代替继承啊。”
冒号解释:“合成是一种解决办法,但也不是没有缺陷。首先,合成的用法不如继承那么简便优雅,这也是许多人喜欢用继承的主要原因;其次,合成不能产生子类型,而有时这正是设计者所需要的;再次,合成无法覆盖基础类的方法,也无法访问它的protected成员;最后,却可能是最大的缺点是:合成的基础类只能是具体类型,不能是抽象类型。”
逗号不明所以:“这能算是缺点吗?”
“如前所述,具体类型的主要任务是创造新对象,如果用作合成或继承的基础类,等于是又承担了原本抽象类型的任务——创造新类型。这不仅有越俎代庖之嫌,而且这两个任务往往也是冲突的。我们曾提出,一个类的服务应该有纯粹性和完备性。一方面,人们希望创造的新对象无所不能,因此更看重服务的完备性,倾向它包含尽可能多的功能;另一方面,人们又希望创造的新类型有所不依,因此更看重服务的纯粹性,倾向它包含尽可能少的功能。”冒号擘肌分理,“妥协的结果是,一个新类型往往只用到基础类型的部分功能,却可能受到其他功能变动的影响。虽然这种影响在良好的封装之下会大大削弱,但也难以完全消弭。”
句号思索片刻,已明其意:“换句话说,以具体类型为代码重用的基本单位,难免颗粒度过大?”
“然也!”冒号的手在空中挽了个花,“其实作为抽象类型的接口也有类似的尴尬:对它的客户类来说,它承诺的服务是多多益善;对它的实现类来说,承诺越多负担却越重。如果能有这样一种可重用的模块,既不像具体类型那样面面俱到,又不像接口那样有名无实,也没有抽象类的多重继承之弊,岂不妙哉?”
“想必就是mixin了!”叹号眼中闪过一道光芒,旋即又暗淡下来,“只可惜Java并不支持啊。”。
“Java不支持就没兴趣了?” 冒号听出他的话里有话,“要成为优秀的程序员,千万不能画地为牢、自我禁锢。始终要保持一颗开放的心,不要拘于某些语言或范式,也不要囿于某些概念或技术。”
叹号的耳根有点发热。
“陌生的理论和技术开始总是拒人千里,不过一旦你了解其问题来源,它们会慢慢变得和蔼可亲起来。”冒号循循善诱,“既然具体类型和现存的两种抽象类型均有不足之处,mixin的产生便合情合理了。它是具体类型与接口类型的一种折衷,既可有抽象方法,也可有具体方法。这一点类似抽象类,但又没有抽象类的多重继承问题。举例来说,Ruby中的Comparable就是一个简单却很典型的mixin。”
问号插话:“Java中也有Comparable接口啊。”
冒号道出其中差异:“Java中的Comparable和C#中的IComparable只有一个抽象的比较方法,而Ruby中的除了有类似的抽象方法——比较(&=&)之外,还提供了小于(&)、小于等于(&=)、等于(==)、大于(&)、大于等于(&=)和介于(between?)等六种具体方法。显而易见,多出的方法均可通过唯一抽象的比较方法来实现。”
引号一点即通:“如此一来,重用Comparable的类只需实现一个抽象方法,便可自动拥有另外六个有用的功能。这既满足了客户类的需求,又不增加实现类的负担。”
“买一送六,这买卖划算!”逗号来劲了。
冒号双眼微眯:“更划算的买卖是Ruby中Enumerable。任何包含该mixin的类只要实现一个遍历方法each,便可免费得到二十多个有关遍历和搜寻的方法。如果再实现比较方法&=&,还可获赠排序和最值方法。相比Java中Enumeration和Iterator接口,优势历然。”
问号很好奇:“为什么称为mixin呢?”
冒号述说由来:“冰淇淋中经常会掺混一些薄荷、香草、巧克力之类的调味料和花生、坚果之类的小零碎,人们管它们叫mix-in。后来被借用来表示一种抽象类型,主要有如下特点:一、抽象性和依赖性:本身没有独立存在的意义,必须融入主体类型才能发挥作用;二、实用性和可重用性:不仅提供接口,还提供部分实现;三、专一性和细粒度性:提供的接口职责明确而单一;四、可选性和边缘性:为主体类型提供非核心的辅助功能。”
“这些特点与风味添加料还真的颇为神似。”叹号想着想着,嘴里不自觉地咂摸了一下。
“虽然C++、Java和C#在语法上尚不支持mixin,但C++可通过多重继承、Java和C#可通过合成和接口来分别模拟mixin。不仅如此,借助切面式编程(AOP),Java和C#甚至可完全实现mixin;借助泛型式编程(GP),C++也能通过模板更好地实现mixin。”冒号点到为止,“就此我们重温前面提到的两个观点。一是编程范式之间的合作性:mixin属于OOP的范畴,但其他编程范式如切面式、泛型式以及二者背后的元编程都能与之相通;二是设计与语言的相关性:C++、Java和C#以及其他诸如Ruby、Python等动态语言对mixin有着不同的支持方式,这在一定程度上会影响系统的OOP设计。”
引号憧憬道:“语言是在发展的,说不定哪天Java也会支持mixin的。”
冒号以实相应:“Java的动态小兄弟Groovy在1.6版已经开始支持mixin ,而C#3.0也新引入了对mixin更友好的语法特性。”
逗号提了一个长期困惑大家的问题:“每当一个新技术出现,我就觉得很矛盾:不追怕落伍,追吧又怕落空。如何判断一个它是昙花一现,还是大势所趋呢?”
“任何技术都是在赞美与批判中成长起来的,预测它们是流星还是恒星绝非易事。就拿OOP来说,上个世纪六十年代就出现了支持OOP的语言,但直到九十年代中后期它才真正成为主流的编程范式。这段时间恐怕比大多数人的程序员生涯还长吧。再说mixin,其实并非今日的重点,介绍它的目的不是盲目追新,而是希望透过其背后的需求驱动点,重新审视现有技术。至于它今后会不会为主流语言所接纳,反倒不是那么重要了。如果一定要我给个建议,那就是八个字:‘不执一法,不舍一法’。”冒号以禅语作答,“软件技术这棵大树经过多年的快速成长,早已枝蔓丛生。欲臻不执不舍之境,当如开班导言中所说:究其根本以知过去,握其主干以知现在,察其生长点以知未来。我之所以倾向于用抽象的方式来谈论技术,正是因为抽象的东西更接近根、更接近干、更接近生长点,从而更普泛深刻,也更稳定持久。”
句号借机问道:“您认为抽象比具体更重要?”
“抽象与具体无所谓孰高孰低,它们只是功用不同而已。”冒号轻轻晃了晃脑袋,“正所谓:必先以术养道,而后以道御术。也就是说,在学习时应注重从具体知识中领悟抽象思想,在应用时应注重用抽象理论来指导具体实践。类似地,软件开发也是如此:从具体需求中构建出抽象模型,再根据抽象模型来完成具体实现。因此,在设计阶段抽象类型尤为关键,而在实现阶段则是具体类型更为重要。”
问号表示理解:“假如从具体需求直接跨到具体实现,省去中间的抽象建模过程,那还用得着架构师和分析师吗?”
“话虽不错,但疑似倒果为因。”冒号洞若观火,“是否有必要抽象建模,关键看项目需求。如果需求简单而稳定,一步到位又何尝不可?甚至软件的开发效率和运行效率还更高——为劈几根细柴而磨刀,值吗?如果需求复杂而多变,引入抽象方有‘磨刀不误砍柴工’之效。毕竟抽象不是目的而是手段,对它片面的追求反会导致过度的设计。”
众人这才发现,给老冒戴顶“抽象派”的帽子是有些冤枉他了,应该是“抽象现实派”的。
冒号续道:“为进一步认识抽象类型,我举个非常实用的例子。它只适用于C++,而不适用于Java和C#。如果你对这一点感到遗憾的话,不要忘记我们的原则:具体实例永远是为抽象思想服务的。”
幻灯一闪,现出一段C++代码——
/**&一个不可复制的类&*/
class&NonCopyable
&&&&protected:
//&非公有构造函数防止创建对象
&&&&&&&&NonCopyable()&{}&&
//&非公有非虚析构函数建议子类非公有继承
&&&&&&&&~NonCopyable()&{}
&&&&private:&
//&私有复制构造函数防止直接的显式复制和通过参数传递的隐式复制
&&&&&&&&NonCopyable(const&NonCopyable&);
//&私有赋值运算符防止通过赋值来复制
&&&&&&&&const&NonCopyable&&operator=(const&NonCopyable&);&//&copy&assignment
/**&NonCopyable的一个私有继承类&*/
class&SingleCopy&:&private&NonCopyable&{};
/**&测试代码&*/
int&main()
&&&&SingleCopy&singleCopy1;
&&&&SingleCopy&copy(singleCopy1);&//&编译器报错:企图复制singleCopy1
&&&&SingleCopy&singleCopy2;
&&&&singleCopy2&=&singleCopy1;&//&编译器报错:企图复制singleCopy1
&&&&return&<span style="color: #;
冒号讲解道:&#8220;有些对象是不希望被复制的。比如一些代表网络连接、数据库连接的资源对象,它们的复制要么意义不大,要么实现困难。由于C++的编译器为每个类提供了默认的复制构造函数(copy constructor)和赋值运算符(assignment operator),要想阻止对象的复制,通常做法是将这两个函数私有化。引入NonCopyable后,它的任何子类将自动拥有不可复制的特性。这样为开发者节省了代码编写量,还免掉了相应的文档说明,使用者也一望而知其意,可说是一石三鸟。虽然NonCopyable从语法上说不是抽象类,但从本质上看是一种类似mixin功能的抽象类型。&#8221;
引号考量一番后说道:&#8220;单就它的功效而言,的确非常符合mixin的四大特点,只是它的子类用的是私有继承,而不是类继承或接口继承。&#8221;
&#8220;你说得很对。可问题是,我们并没有要求mixin或者trait一定要通过继承的方式来重用啊?事实上,有些mixin甚至可在运行期间产生,还能克服继承的静态缺陷。即使采用继承,一般也不满足&#8216;is-a&#8217;关系。你总不能说草莓冰淇淋是一种草莓吧?&#8221;冒号淡淡地说,&#8220;先前你们总结出抽象类型有两个特征:需要继承和无法实例化,但它们并非本质,关键还是它的目的——为类型服务。提供可被继承的超类型只是一种服务方式,却非唯一的方式;无法实例化只因它不是为对象服务的,禁止实例化不过是语法上的加强,目的是让用户在编译期间就能发现用法错误。其实,即便NonCopyable类的构造函数是公有的,也不会有人去实例化。原因很简单,它的价值只有通过子类才能体现,这是由其抽象的本性所决定的。&#8221;
逗号有些奇怪:&#8220;为什么在Java中就没有类似的对象复制问题呢?&#8221;
&#8220;这是一个非常基础的问题,请容我下次再回答你。&#8221;冒号破天荒地没有立即解疑,&#8220;以下重点还是放在接口和抽象类上面,我们称之为基本抽象类型,以别于mixin、trait等其他抽象类型。我们先从语法上简单地对比一下这两种类型。&#8221;
屏幕上显示出一张表格(如表10-1所示)——
表 10-1. Java/C#的抽象类与接口在语法上的区别
提供实现代码
拥有非public成员
拥有域成员
否(Java中的static final域成员除外)
拥有static成员
否(Java中的static final域成员除外)
拥有非abstract方法成员
方法成员的默认修饰符
public abstract(Java:可选;C#:不能含有任何修饰符)
域成员的默认修饰符
Java:public static final;C#:不允许域成员
冒号简明扼要地总结:&#8220;C#的语法与Java的稍有不同,但二者在接口与抽象类的关键区别上还是一致的:接口不能提供实现但能多重继承,抽象类则正相反;接口只能包含公有的、非静态的、抽象的方法成员,抽象类则无此限制。&#8221;
问号言明难处:&#8220;从语法上区分它们并不难,难的是从设计上区分它们。&#8221;
逗号实话实说:&#8220;按照上节课&#8216;提倡接口继承,慎用实现继承&#8217;的方针,应该倾向用接口而非抽象类。但总觉得接口太虚了,没有抽象类实在。&#8221;
引号反驳:&#8220;要说实在,具体类型更实在啊。&#8221;
叹号坦言:&#8220;在编程中经常需要用到标准的或第三方的类库,可查起API来经常是左一个接口右一个接口的,迟迟不见具体类型现身,心里哪个急啊!&#8221;
冒号打了个比方:&#8220;如果到包子铺买包子,作为客户你也许会认为包子是具体类型,但对提供包子的人来说它却是抽象类型。他一定会问你:是要肉包、菜包还是豆沙包?是要蒸包、煎包还是小笼包?他的铺子开得越专业,给你出的选择题越多,众口难调嘛。同样道理, 要建一个高度可重用的类库,一些接口是必不可少的。&#8221;
句号悟道:&#8220;接口的意义就在于:提供者不是擅作主张,而是推迟决定,让客户选择实现方式。&#8221;
&#8220;言之有理!类似地,抽象类的意义就在于:父类推迟决定,让子类选择实现方式。&#8216;推迟&#8217;二字道出了抽象类型除创建类型之外的另一功用:提供动态节点。如果是具体类型,节点已经固定,没有太多变化的余地。反过来,要使节点动态化,一般通过多态来实现。由此,抽象类型常常与多态机制形影不离。&#8221;冒号稍加引申,&#8220;就说前面的验证类吧,用模板方法模式实现的Authenticator类将关键的方法交给子类SimpleAuthenticator或Sha1Authenticator处理,用策略模式实现的Authenticator类将关键的方法交给内嵌接口KeyValueKeeper和Encrypter的实现类处理。后者的两次接口继承比前者的一次实现继承多了一个动态节点,因而更加灵活。这也是为什么一个需要(M&#215;N)个实现类,一个只要(M+N)个的原因。当然,这也不是完全没有代价的。比如要创建一个用SHA-1算法加密的验证类实例,两种方法对比如下——&#8221;
模板方法模式:new Sha1Authenticator()
策略模式:
new Authenticator(new MemoryKeeper(), new Sha1Encrypter())
冒号指点着黑板:&#8220;显然,后者无论是使用上还是性能上都比前者稍有不如。但权衡利弊,多数时候它仍是更好的选择。&#8221;
&#8220;包子铺的包子用料种类越多、做法越多,买一个包子越费事。但只要不到饿得发昏的地步,大家还是更喜欢花样更多的包子铺。看来我也不该再抱怨类库的接口过多了。&#8221;叹号心下释然。
&#8220;大家再看看这个电脑主板,开过机箱攒过机的人应该对它并不陌生。&#8221;冒号终于亮出了蓄藏已久的道具, &#8220;上面密密麻麻地布满了各种元件,那是它的实部,而我们关注的是它的虚部——各种插槽和接口,包括CPU插槽、内存插槽、PCI插槽、AGP插槽、ATA接口、PS/2接口、USB接口以及其他林林总总的扩展插槽等等。这些接口的存在,使得主板与CPU、内存条、外围设备以及扩展卡等不必硬性焊接在一起,大大增强了电脑主机的可定制性。&#8221;
引号受到启发:&#8220;主板与其他硬件就好比一个个的具体类型,那些插槽和接口就相当于一个个的接口类型。所有的硬件以接口为桥来组装合成,以机箱为壳来封装隐藏,一个新的具体类型——具有完整功能的主机便产生了。&#8221;
&#8220;比喻非常到位!&#8221; 冒号很满意,&#8220;不过准确地说,与接口类型对应的不是物理接口,而是接口规范。如果仅仅是物理接口,只能保证该接口适用于某种特定型号的硬件产品,却不能保证同时适用于其他型号或者其他类型的硬件。以大家熟悉的USB(Universal Serial Bus)接口为例,它能接入各种外部设备,包括鼠标、键盘、打印机、外置硬盘、闪存和形形色色的数码产品。这当然不是偶然的,因为所有厂家在生产这些硬件时均遵循了相同的业界标准——USB协议规范。换言之,任何一个与USB接口兼容的设备,都可看作是实现了此接口的具体类型,而主机对该设备的自动识别能力则可看作一种多态机制。&#8221;
&#8220;这下我更深刻地理解那句话了:接口继承不是为了重用,而是为了被重用。&#8221;句号品味道,&#8220;比如一个鼠标,可以有串行接口、PS/2接口、USB接口或者无线接口,还可以同时拥有多个不同类型的接口。无论怎样,它本身都是完整的产品,根本不需要重用主机上的其他硬件,它实现某些接口的目的完全是为了能被主机所用。&#8221;
逗号意识到:&#8220;看样子,硬件设计也需要OOP思想呢。&#8221;
&#8220;相比软件设计师,硬件设计师往往能更好地贯彻OOP的理念。&#8221;冒号加强了语气,&#8220;他们的对象化概念更清晰更自然,因为硬件模块比软件模块更实在更具体;他们更注重设计,因为硬件比软件的修改成本大得多;他们更注重设计重用,因为硬件重新发明轮子的成本普遍很高;他们更注重实现重用,因为无法在举手之间完成&#8216;复制-粘贴&#8217;工作;他们更注重接口明确、封装完好,因为把内部的接口或结构暴露在外不仅难看,还容易带来缠绕、磨损、短路等问题;他们采用合成和接口来组装模块,因为硬件没有类似实现继承的机制。&#8221;
&#8220;看起来我们真得向硬件设计师取经了。&#8221;叹号有些信服了。
冒号旧话重提:&#8220;我们曾对OOP有过这样的描述:如果把OOP系统看作民主制社会,每个对象是独立而平等的公民,那么封装使得公民拥有个体身份,继承使得公民拥有家庭身份,多态使得公民拥有社会身份。补充一下,其中的继承主要指类继承,多态主要指接口继承带来的多态。经过这段时间的学习,大家对此有何见解?&#8221;
问号发表看法:&#8220;广义封装让每个类成为独立的模块,从而让每个对象具备了个体身份。狭义封装又进一步地把类的接口与实现分离,从而让每个对象具有显著的外在行为和隐藏的内在特性。继承机制可使一个类成为其他类的子类或父类,从而确立了对象在类型家族中的身份。至于多态嘛,嗯。。。&#8221;
问号努力想抓住若隐若现的头绪。
句号接过话头:&#8220;一个公民的社会身份是指他在社会中所处的地位和扮演的角色。比如,一个人在学校里是学生,在公司里是职员,在商店里是顾客,他真正的个体身份往往是被掩盖的。同样地,一个对象在与外界联系时,通常不以其实际类型的身份出现,而是在不同的场合下以不同的抽象类型的身份出现。我想,这大概就是多态带来的社会身份吧。&#8221;
&#8220;这种社会身份的意义何在?&#8221;冒号不动声色地问。
句号接着回答:&#8220;社会身份既是一种资格也是一种义务。比如在列车上有人得了急病,可以通过广播找医生。人们不用事先知道来者的具体个人身份,只要他是医生,就会放心地让他第一时间去救人。&#8221;
&#8220;这个比喻很恰当。&#8221;冒号赞道,&#8220;不用事先知道个人身份,不正说明广播呼叫的对象是一个多态的抽象类型吗?同理,当一个具体类型显式继承了一个接口,它的对象便拥有了个体身份之外社会身份:有资格以该接口的形式与外界打交道,也有义务履行该接口的职责。&#8221;
&#8220;咦,那为什么把社会身份归功于多态而不是继承呢?&#8221;问号发出疑问。
冒号释疑:&#8220;继承自然有功劳,毕竟子类型多态要建立在它的基础上。但如果没有多态机制,要确保一个对象的实际方法而不是其超类型的方法被调用,必须将其还原为具体类型,从而使社会身份变得几乎有名无实。&#8221;
问号憬然醒悟。
冒号继续深入:&#8220;对象每多一种社会身份,便多一条与外界交流的渠道。为什么遮遮掩掩地不肯以本来面目示人呢?非是羞于见人,盖因一般的具体类型在公共场合是不为人知的,只有少数核心库里的核心类是例外。即使侥幸被认识,也难被认可,因为那会以代码的复杂度和耦合度为代价。社会身份则不然,它远比一般的个体身份更容易被接受。&#8221;
逗号举出例证:&#8220;这就好比上课得有学生证,上班得有工作证,上火车得有火车票,上飞机得有登机牌。只要不是炙手可热的公众人物,很多场合都是认牌认证不认人的。&#8221;
&#8220;道理人人都懂,可总有不少人以为自己编写的类都是明星大腕,大有&#8216;天下谁人不识我&#8217;的豪迈,无牌无证就敢到处乱窜。更有甚者,不用多态就算了,连封装也不要,简直是在裸奔嘛。&#8221;冒号揶揄道。
全班笑不可仰。
冒号恢复肃容:&#8220;谈到这里,我们不能不再次提到&#8216;针对接口编程&#8217;的基本原则。它有一种建立于数据抽象之上的形式,能让用户只关心抽象数据类型的API接口而无视其具体实现。不过,它至少有两大局限。其一,虽然在接口不变的情况下,实现代码的改变不会影响客户代码,但仍需要重新编译,对于需要头文件的C++来说则需要更多的编译链接时间。其二,虽然相同的接口可以有多种实现方法,但它们不能同时并存,更无法动态切换。于是,另一种建立于多态抽象之上的形式应运而生。它把抽象数据类型隐藏在抽象类型的背后,从而提升了抽象接口。同一个抽象接口允许有多种实现并存,且能动态切换,新增、删除或修改某种实现也不会导致其他代码的修改或重新编译。方才我们从主体类的角度来看,它的对象尽量以社会身份参与社会活动;现在再从客户类的角度看,它会尽量召集有社会身份的对象。两相结合,以社会身份而非个人身份作为公民之间联系的纽带,正是针对接口而非实现来编程的社会现实版。&#8221;
问号有所顾虑:&#8220;可是,有不少具体类型并没有实现任何接口,也就没有社会身份。&#8221;
&#8220;排除设计不良的因素,没有抽象超类型的具体类型最常见的有两种可能。一种是与世隔绝,一辈子几乎足不出户,至多在小圈子里活动。典型的有非公有类、内部类、局部类等等。一种是名满天下,他的脸就是一张天然名片,他的个人身份也就是社会身份。典型的有基本数据类型、字符串类型、日期类型等通用数据类型以及特定领域的通用数据类型。可见,个人身份与社会身份并无绝对的界限。同样,家庭身份与社会身份也有交合之处,正如名门望族也可成为社会身份一样。典型的有Java IO库中的InputStream和OutputStream、Reader和Writer,以及UI库中的Component和JComponent等等。&#8221;冒号信手拈来,&#8220;因此我们谈到的社会身份,不必拘泥于接口,甚至不必限于抽象类型,关键是该类型是否具备了足够的通用性和规范性、稳定性和独立性、灵活性和专业性。还是应了那句话:抽象不是目的而是手段。再拿现实社会说事,每种社会身份都代表了个体与社会缔结的一种契约,它有如下的特点:独立而稳定——先于个体而存在,且不随个体的变化而变化;公开而权威——为人所知、为人所信;规范而开放——制定的协议标准明确,且允许个体在遵守协议的前提下百花齐放。毫无疑问,推行契约制将使社会大受其惠。首先,相同身份的个体可相互替换、新型个体可随时加入,而且不会影响整体框架和流程,保证了系统的灵活性和扩展性。其次,整体不因某一个体的变故而受冲击,保证了系统的稳定性和可靠性;最后,个体角色清晰、分工明确,保证了系统的规范性和可读性。&#8221;
引号非常注重概念:&#8220;社会身份所代表的契约对应的正是规范抽象吧。&#8221;
&#8220;每种身份都是规范抽象的结果。&#8221; 冒号推而广之,&#8220;具体地说,个体身份对应的规范抽象借助封装,以数据抽象(data abstraction)的形式出现;家庭身份对应的规范抽象借助继承,以类型层级(type hierarchy)的形式出现;社会身份对应的规范抽象借助多态,以多态抽象(polymorphic abstraction)的形式出现。至此,我们分别从行为和规范两个角度分别诠释了OOP的三大特征与公民的三大身份之间的关系。这也非常合乎情理:一个合理设计和实现的类,其对象的行为与规范本应保持一致。&#8221;
句号欲印证自己的想法:&#8220;我的理解是,接口是一个携带契约的角色标签,接口继承的作用就是静态地为对象贴上该标签,而多态机制的作用就是动态地让对象发挥该角色。因此,要赋予对象某个角色,就应该让相应的类去继承相应的接口。&#8221;
&#8220;你的前半部分表述得非常精当,后半部分则稍有瑕疵。&#8221;冒号评论道,&#8220;接口可用来代表角色,但角色却不一定要通过接口。正如你提到的,接口继承是静态的,而角色却可能是动态的。比如学生毕业后变成职员,职员升迁后变成经理等等。对于静态类型语言来说,这类问题的解决单靠接口继承是不够的,还需要利用合成等手段,或者利用前面提到的其他抽象类型如mixin或trait。&#8221;
叹号仍有疑惑:&#8220;接口的意义已经很清楚了,那抽象类呢?它们的区别真的很大吗?&#8221;
&#8220;我们已经从语法上比较了它们的区别,那些只是表象的东西。如果对语言规则的理解仅仅停留于语法层面,那么它更多体现为对实现的束缚。只有提升到语义层面,它才更多体现为对设计的保障。&#8221;冒号保持一贯高举高打的风格,&#8220;从语义上看,抽象类与接口的区别,并不比它与具体类的区别小多少。&#8221;
叹号错愕不已:&#8220;怎么可能?抽象类与接口好歹都是抽象类型啊。&#8221;
冒号反诘:&#8220;为什么不说抽象类与具体类好歹都是类呢?&#8221;
叹号一时无语。
&#8220;先看段历史吧。&#8221;冒号幽幽地说,&#8220;开始C++是没有抽象类型的,直到1989年C++ Release 2.0发布前的最后一刻,Bjarne Stroustrup才力排众议引入抽象类。从C++的前身C with Classes 开始算起,其间已经整整十年了。即便如此,它的意义在当时仍不为大多数人所认识。推出一个看似小小的语法特征竟会如此艰难,恐怕远远超出诸位的想象吧!有人幻想只通过看语法书就能完全领会语言的精髓,又与痴人说梦何异?&#8221;
冒号的声音渐渐激昂起来。
逗号为自己找到了安慰:&#8220;难怪当初学到抽象类时,总感到只知其意而不知其用。&#8221;
冒号紧接着说:&#8220;抽象类的出现,让两种不同角色的类在语法上有了明确的界定:具体类描述对象,重在实现;抽象类描述规范,重在接口。这种分工降低了用户与实现者之间的耦合度,大大减少了代码的维护成本以及编译时间。由于抽象类不是为了创建对象,它的实例化自然是没有意义的。又由于它是接口规范,在子类没有实现其所有规范之前,是不能实例化的,否则规范岂不成了一纸空文?在没有抽象类的语法之前,要实现类似的功能,唯一的办法是:在本该抽象的方法被调用时强行中止程序。烦琐丑陋不说,还只能在运行期间捕捉错误。在纯虚函数(pure virtual function)——相当于Java和C#中的抽象方法——被引入之后,任何含有抽象方法的类都是抽象类,编译器将保证它不会被实例化。&#8221;
问号连连点头:&#8220;从这个角度来理解抽象类的语法,一切都顺理成章了。不过,抽象类与接口的区别好像还是没有看到。&#8221;
谈到兴头,冒号出言更如下阪走丸:&#8220;从具体类中分离出抽象类是一次质的飞跃,从抽象类中进一步地分离出接口则是另一次飞跃。Java推出接口类型之时同样饱受质疑,最终还是经受了实践的考验,后又为C#所采纳。其实最初C++的抽象类是为了定义一组协议并强令各子类遵守,实质上正是Java和C#中的接口所起的作用。但在协议规范的实现过程中,可能会产生一些不完全实现类。允许这种类的存在固然是一种灵活的举措,但必须认识到它们与纯规范的抽象类已判若云泥。打个比方,如果把对象看作产品,把具体类看作一个制作产品的模具,那么接口就是模具的规格标准,而抽象类是在模具加工过程中产生的半成品。接口与抽象类无法实例化,模具规格与模具半成品也不能直接制作产品;一个具体类可以有多个接口,一个模具也可有多个不同方面的规格;一个具体类至多只能继承一个抽象类,一个模具也至多只能在一种模具半成品的基础上直接加工。&#8221;
引号细加回味:&#8220;如果具体类、抽象类和接口分别对应于模具、模具半成品和模具规格,那后两者的区别的确比前两者的区别还大。可是假如一个抽象类完全没有任何实现呢?抛开多重继承的限制,它与接口又有何区别呢?&#8221;
冒号辨析其别:&#8220;一个抽象类可以没有任何实现,但也随时可以加入实现。接口则不同,永远都不能有实现代码。这正是引入关键字interface的目的,明明白白地表明:此乃规范集合所在,杜绝任何自以为是、画蛇添足的实现。初看似乎不合常理:这不是自缚手脚、自废武功吗?殊不知自由源于自制。许多人为了贪恋一点点代码重用,总忍不住把一些实现放在本该只是规范的地方。一来,这模糊了规范与实现的界限,背离了接口与实现相分离的设计初衷。要知道,再完美的实现都有改动的余地,将其捆绑到规范中只会增加不稳定因素;再完美的实现也不应该影响其他的实现,先入为主只会降低灵活性。二来,带有实现的抽象类无法用于合成,必须通过类继承才能起作用,而实现继承的弊端我们已经见识过了。在有些情况下,规范的实现比较复杂,需要渐进实现,保留一些中间状态的抽象类也是合理的,但最初的接口最好保留。总不能因为有了模具半成品,就抛弃模具规格吧?以Java Collections Framework为例,既规范了Collection、Set、List、Map等接口,又为这些接口提供了抽象类和具体类,从而给了用户三种选择:直接利用具体类、扩展抽象类、直接实现接口,方便程度递减而灵活程度递增。&#8221;
句号进行反思:&#8220;我在想,为什么以前对接口总有本能的排斥心理?原因在于:满脑子更多想的是怎么让程序工作,而不是想怎么让程序工作得更好。因此更重视代码实现,比较忽视规范设计。&#8221;
众人皆有同感。
&#8220;确实,在缺乏设计观念的人看来,使用接口和脱裤放屁差不多。&#8221;冒号轻笑道,&#8220;特别需要注意一种常见的说法:接口是为了克服Java或C#中抽象类不能多重继承的缺点。这句话具有相当大的误导性,因为该处的多重继承是指多重实现继承,而接口甚至连单重实现继承都做不到!许多人对接口与抽象类的认识之所以模糊不清,原因是他们习惯于从定义和语法中寻找表象的答案,不习惯从本源和语义上进行本质的分析。然而不可否认,毕竟接口与抽象类提供了相似的抽象机制,在实践中往往确难抉择。因此光从语法上对比二者的差别是远远不够的,需要进一步在语义上进行对比(如表10-2所示)——&#8221;
表 10-2. Java/C#的抽象类与接口在语义上的区别
冒号展开叙述:&#8220;先从本性上看:接口是一套功能规范集合,因此相同的接口代表相同的功能,多表示&#8216;can-do&#8217;关系,常用后缀为&#8216;-able&#8217;的形容词命名,如Comparable、Runnable、Cloneable等等。接口一般表述的是对象的边缘特征,或者说一个对象在某一方面的特征,因此能在本质不同的类之间建立起横向联系。由于一个对象可拥有多方面的角色特征,故而可有多种接口。与之相对地,抽象类是一类对象的本质属性的抽象,因此相同的抽象基类代表相同的种类,多表示&#8216;is-a&#8217;关系,常用名词命名。抽象类一般表述的是对象的核心特征,只能在本质相同的类之间沿着继承树建立起纵向联系。由于一个对象通常只有一个核心,故而只能有一种基类。再从目的上看:接口是为了规范重用,让一个规范有多种实现,看重的是可置换性;抽象类主要是为了代码重用,能逐级分步实现基类的抽象方法,看重的是可扩展性。&#8221;
叹号追问:&#8220;演变指的又是什么呢?&#8221;
冒号答道:&#8220;严格说来,演变不属语义范畴,属于语法规则的一个推论。在系统演变过程中,接口与抽象类的表现差异很大。接口由于是被广泛采用的规范,相当于行业标准,一经确立不能轻易改动。一旦被广泛采用,它的任何改动——包括增减接口、修改接口的签名或规范——将波及整个系统,必须慎之又慎。抽象类的演变则没有那么困难,一则它在系统中用得没有接口那么广泛,更多地是家庭身份而非社会身份;二则它可随时新增域成员或有默认实现的方法成员,所有子类将自动得以扩充。这是抽象类的最大优点之一。不过接口也有抽象类所不具备的优点,虽然自身难以演化,但很容易让其他类型演化为该接口的子类型。例如,JDK5.0之前的StringBuffer、CharBuffer、Writer和PrintStream本是互不相关的,在引进了接口Appendable并让以上类实现该接口后,它们便有了横向联系,均可作为格式化输出类Formatter的输出目标。&#8221;
问号还留有一个疑点:&#8220;现在接口与抽象类之间的差异是越来越清晰了,我只是有一点一直没想通:标记接口究竟有什么用?它一个方法都没有,也就谈不上规范,也无法利用多态机制,继承这类接口又有何意义呢?&#8221;
逗号随口说:&#8220;这就好比有些社会身份是光挂名头不干事的虚衔,不足为奇。&#8221;
冒号回应道:&#8220;先需澄清一点,一个类型的规范不限于单个的方法,类型整体上也有规范,比如主要目的、适用场合、限定条件、类不变量等等。另外,接口的目的是为了产生多态类型,不能只看到&#8216;多态&#8217;而忽略&#8216;类型&#8217;。一个接口哪怕没有一个方法,也是有意义的。首先,接口是一种类型,有严格的语法保障和明确的语义提示,这也是静态类型的优势所在。让一个具体类继承特定接口,既凸显了设计者的用意,也授予用户针对性地处理该类型的权力。比如java.util.EventListener接口为所有的事件监听器提供了统一的根类型。其次,有时需要对某些类型提出特殊要求、提供特殊服务或进行特殊处理,而这些并不能通过公有方法来办到,也没有其他有效的语言支持。标记接口可担此任,成为类型元数据(metadata)的载体。比如给一个类贴上一个java.io.Serializable的标签,它的对象便能被序列化,具体工作由JVM来完成。用户也可以通过自定义私有的writeObject 、readObject等方法来定制序列化方式。值得指出的是,当标记接口仅仅用于元数据时,更好的办法是采用属性导向式编程(&#64;OP),Java中的annotation、C#中的attribute即作此用。&#8221;
逗号摸了摸后脑勺:&#8220;原来标记接口并非虚有其名,还是在偷偷地干实事呢。&#8221;
冒号见时候已到,准备落下帷幕:&#8220;至此,我们探讨了OOP中最基本的机制——封装、最独特的机制——继承、最重要的机制——多态。在今天的课结束之前,请大家每人用一个关键词来形容自己眼中的OOP,并作简要说明。&#8221;
引号说:&#8220;责任——在契约化的公民社会中,最重要的是对自己、对家庭、对社会的责任感。&#8221;
问号说:&#8220;变化——采用封装以防个人之变,慎用继承以防家庭之变,采用多态以防社会之变。&#8221;
逗号说:&#8220;分合——数据与运算结合,接口与实现分离。&#8221;
句号说:&#8220;抽象——无论是封装、继承还是多态,都是施诸众对象之上的抽象机制。&#8221;
叹号说:&#8220;虚伪——用封装来掩盖内心,用多态来掩盖外表,提倡继承责任却不提倡继承财富!&#8221;
冒号欣赞道:&#8220;不错不错,虽然角度各异,但均深中肯綮。我也大可安心下课了!&#8221;
众人也乐得打道回府。
C#中表示列表和映射的抽象类型(具体类型)分别是IList(List)和IDictionary(Dictionary)。
此处主要指以继承为基础的抽象类型,如接口与抽象类。
在C++中,如果一个类不含数据只含抽象的成员函数(即pure virtual function),则该类有时被称为纯抽象类(pure abstract class),与Java和C#中的interface的功用大致相当。
参考文献【4】和【5】对trait有深入的介绍,并与mixin作了详细的比较。
该问题的一个解决方式是依赖注射,即把创建被合成对象的职责交给外界。但严格说来这不是合成,而是聚合或关联。它们之间的详细区别请参见&#167;11.2。
C++可利用CRTP(Curiously Recurring Template Pattern)的惯用法来实现mixin。
指C#3.0的扩展方法(extension method)。
第一个支持OOP的语言是Simula 67(1967年)。
例外情形:Java的interface可含static final域成员,C#的interface还可含property、event或indexer成员。
虽然具体类型有可能被继承,但通常并不提倡。
据参考文献【1】中介绍,一些大型系统在引入抽象类后,编译时间少了一个数量级。
接口也可能描述对象的核心特征,但一个类至多一个这样的接口。
由于类继承同时也继承了接口,抽象类也能规范重用,但更侧重代码重用。
前提是新增的方法成员不与子类型的方法发生冲突。
严格说来,还要求该类所有非static非transient的域都是可序列化的。
具体类型是创建对象的模板,抽象类型是创建类型的模块。
抽象数据类型的核心是数据抽象,而抽象类型的核心是多态抽象。
抽象类型除了接口和抽象类外,还有mixin、trait等,它们用来克服以下问题——
合成的缺陷:
用法不如继承那么简便优雅;
不能产生子类型;
无法覆盖基础类的方法,也无法访问它的protected成员;
不能以抽象类型为基础类。
具体类型的矛盾与缺陷:
作为创造对象的单位,功能越多越好;
作为可重用的单位,功能越少越好。
不宜被继承。
接口的矛盾与缺陷:
客户类希望它提供尽可能多的服务;
实现类希望尽可能少的实现代码。
无法代码重用。
抽象类的缺陷:
多重类继承或复杂晦涩或未获支持。
mixin的特点:抽象性和依赖性;实用性和可重用性;专一性和细粒度性;可选性和边缘性。
在设计阶段,从具体需求中构建出抽象模型,此时抽象类型尤为关键;在实现阶段,根据抽象模型来完成具体实现,此时具体类型更为重要。
抽象类型除了能创建类型外,还能提供动态节点,以增加软件的灵活性和可扩展性。
社会身份代表了个体与社会缔结的一种契约,具有独立、稳定、公开、权威、规范、开放等特点。
以社会身份作为公民之间联系的纽带,以接口类型作为对象之间联系的纽带。
系统中广泛用于模块之间通讯的数据类型相当于社会身份,提倡使用接口类型。但也不必拘泥,甚至不必限于抽象类型,关键是要确保该类型的通用性、规范性、稳定性、独立性、灵活性和专业性。
个体身份对应的规范抽象借助封装,以数据抽象的形式出现;家庭身份对应的规范抽象借助继承,以类型层级的形式出现;社会身份对应的规范抽象借助多态,以多态抽象的形式出现。
从具体类中分离出抽象类是一次质的飞跃,从抽象类中分离出接口则是另一次飞跃。
接口与抽象类的语法区别:接口不能提供实现但能多重继承,抽象类则正相反;接口只能包含公有的、非静态的、抽象的方法成员,抽象类则无此限制。
接口与抽象类的语义区别:接口是一套功能规范集合,相同的接口代表相同的功能,多表示&#8220;can-do&#8221;关系,一般是对象的边缘特征,在本质不同的类型之间建立横向联系;抽象类是一类对象的本质属性的抽象,相同的抽象基类代表相同的种类,多表示&#8220;is-a&#8221;关系,一般是对象的核心特征,在本质相同的类型之间建立纵向联系。接口看重规范重用和可置换性;抽象类看重代码重用和可扩展性。
接口与抽象类的演变:抽象类的演变较为容易;接口自身很难演变,但很容易让其他类型演变为它的子类型。
标记接口除了能定义类型外,还可作为类型元数据的载体。
&#8220;&#8221;参考
Bjarne Stroustrup.The Design and Evolution of C++.Reading, MA:Addison-Wesley,1
Joshua Bloch.Effective Java: Programming Language Guide.Boston, MA:Addison-Wesley,
Nathanael Sch&#228;rli,St&#233;phane Ducasse,Oscar Nierstrasz,Andrew P. Black.Traits: Composable Units of Behaviour.ECOOP,2003,LNCS &#
St&#233;phane Ducasse,Oscar Nierstrasz,Nathanael Sch&#228;rli,Roel Wuyts,Andrew P. Black.Traits: A Mechanism for Fine-grained Reuse.ACM Transactions,):331-388
Wikipedia.Mixin.
10-01 多态类型在何种程度上解放了静态类型的束缚?
10-02 请总结参数多态与子类型多态的特点和适用场合。
10-03 为什么抽象类型如此重要?
10-04 你认为有必要引入mixin或trait类型吗?
10-05 区分接口与抽象类的意义何在?
10-06 你常有往接口中放置代码的冲动吗?
10-07 如何理解文中&#8220;多态使得公民拥有社会身份&#8221;这句话?
10-08 &#8220;针对接口编程&#8221;与&#8220;公民之间以社会身份互相交流&#8221;有何相似之处?
10-09 你是如何理解OOP中抽象、封装、继承和多态的?
10-10 每当一项新技术出现时,你通常抱什么态度?
10-11 你会在编程中对某些语法上的限制感到恼火吗?
10-12 在理解或比较一些编程概念时,你是更习惯从定义和语法的角度,还是更习惯从本源和语义的角度?
10-13 本课与前课均提到了编程与武术相通之处:攻守兼备,动静得宜,刚柔并济,虚实结合。对此你有何心得体会?
友情提示:如果您对本文感兴趣,欢迎到上发表。
又及:《冒号课堂》一书即日上市,详情请见:。
评论 - 344
博客搬家:
《冒号课堂》一书于2009年10月上市,详情请见
留言簿(17)
随笔分类(61)
随笔档案(61)
文章分类(1)
文章档案(1)
积分与排名
阅读排行榜
评论排行榜}

我要回帖

更多关于 微信搭讪第一句 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信