StupidBeauty
Read times:3503Posted at:Sat Sep 2 02:29:29 2017 - no title specified

《C++面向对象软件设计及构建》文章翻译:1.6泛化,1.6 Generalization

泛化,标识的是,一组实体之间的相似性。这种相似性,可能体现在属性中、可能体现在行为中,也可能在属性和行为中都有体现。例如,这样一句话:“所有的窗口都有一个标题”,表达的是,所有被认为是窗口的实体,都具有一个共同的属性。类似地,这样一句话:“所有的窗口都能够改变大小”,表达的是,所有的窗口都提供了一个共有的行为。泛化,通常狠容易识别出来,因为,它们都包含有“全部”“每个”这样的词。

因此,泛化,可按照如下文字来定义:

泛化

对于抽象事物的共有属性的标识以及可能情况下的组织。


这个定义表明,泛化,并不是抽象,尽管这两个东西经常会被搞混了。抽象,其目的是将实体的描述简化。而泛化,其目的是寻找这些抽象之间的共有属性。

显然,在狠多学习项目中,泛化都显得狠重要且流行。例如,在科学和数学中,各种定律和定理的陈述语言,就是泛化的形式 - 它们声明,某组事物拥有某个共同的属性:泛化的能力越强,该个泛化能够涵盖的事物就越多。对于性质的基本组成的寻找,表明了,物理学家们想要找到一种能够涵盖宇宙中所有物质的泛化手段。

泛化,在软件中也同样重要。在构建软件系统的过程中,狠大一部分努力,就是为了,让系统中的各个部分能够以最通用的方式来操作。在某些情况下,这就意味着,要仔细设计整个系统,使得,它能够处理任意 数量 的相同类型的事物。例如,可能会预期系统能够处理任意行数的输入内容。而另外一些情况中,主要的设计问题在于,如何处理 不同 种类或类型的事物。例如,可能会预期系统能够处理不同格式的文件中的输入内容,或者,预期系统能够处理本地文件和远程文件。泛化,在软件中提供了一种处理这些问题的手段。

泛化 的四种方式中,有一种是 层次结构 ,具体 来说,就是,将共有属性组织成一个树型结构。 在每个子树的根节点处,能够找到 该个根节点的所有后代所共有的属性和行为。 这种特殊的树结构,被称作泛化/特化层次结构,因为, 根节点处提供了较通用的属性,由所有的后代所共享, 而那些后代呢 ,一般会向其中加入特殊 的属性,使得它们都显得与其邻居节点和邻居节点的后代节点不同。

泛化 的第二种形式是 通用 ,具体 来说,共有属性是利用一个参数来表达的。各种特化之间, 就是通过它们所提供的参数来区分的。例如 ,利用通用 性方式,就可以实现,利用 一个泛化的“由任意事物组成的栈”来表达栈这种结构的共有属性,其中 ,“任意事物”, 即是我们所说的参数。对于 这种泛化的特化形式,包括,“整数组成的栈”和“字符组成的栈”。

泛化 的第三种形式,是, 多态 。多态 ,专注于算法中的共同点。算法 中,可能会包含有嵌套的 if-then-else(或者 “分情况语句” )逻辑 这个逻辑会检测它本身是在对哪种具体类型的对象进行操作。 在算法中,会根据对象的具体类型来做出一些操作。然而 ,在狠多算法中, 要进行的操作都是相同的,仅仅 是它们对之进行操作的对象的类型不同。利用多态 ,就可以做到, 将这种嵌套式的逻辑 (或者 分情况处理 )折叠 成一个单一的情况,将那些不同的对象类型当成统一的形式来对待。利用 一种称为 动态绑定 的机制, 就可以在算法中做到, 让对象自己来决定,要进行哪种操作,以便对这次算法调用做出响应。因此 ,算法本身就不需要知道对象的确切类型。算法 只需要知道,该个对象能够以某种方式对此次调用做出响应。

泛化 的第四种形式是 模式 。模式 ,表示的是,对于常见的设计问题的通用解决方案 (关键 的组件和关系 ) 。单个组件 的属性和行为,只是被部分定义, 以使得模式能够 被解释 (interpreted)且应用到广泛 的情景之中。例如, “带轮子的车子”,这样一个模式,可能定义 为由 “轮子”“ “框架” “车身” “能源” 各个组件组成。 这个模式中,还会展示, 这些组件是如何按照互相之间 的关系组装起来的 (例如, 轴必须连接到两个轮子上 ) ,并且 可以按照不同的方式来解释,以解决针对特定方面 的问题:速度 ;续航时间;载重;能源;可用材料 ;以及其它因素。对于 带轮子的车子这种模式,已经有这些例子的: “汽车”“马车” “牛车”和“月球 ”。


层次结构


基于泛化/特化关系而将组件组织起来的层次结构,是面向对象编程中的一个重要的武器。尽管,这种组织关系的功用,要在更深入的研究之后才能被完全认识到,但是,最起码在妳判断它所扮演角色的过程中也能起到帮助作用。下图展示的是,一个典型的图形用户界面系统中,各个组件是如何组织起来的。最通用的组件,窗口,拥有位置(坐标,表示该窗口位于屏幕上什么地方)和形状(高度和宽度)两个属性,且拥有一个行为,使得它可以被移动位置以及改变大小。另外还有一些特殊类型的窗口,包括以下种类:带有一个下拉菜单栏(Frame);支持绘制图形形状(Canvas);具有交互功能(Items);维护一个预定义好的条目(Items)布局(Panel);以及,允许显示可滚动的简单文字内容(TextWindow)。另外还有多种交互式组件,它们被展示为 Items 的特化类型。

一个泛化,和它的特化,二者之间,通常被认为具有一种“是一个”关系,如同下面图片中所展示的那样,“条目(Item)是一个窗口(Window)”。此处的“是一个”术语,反映的是,特化事物具有泛化事物的所有属性和行为。

在面向对象编程活动中,对于层次结构,可如下定义:

层次结构

将抽象事物组织成一个有向图,在这个有向图中,各条边都表示一个“是一个关系”,这个关系的双方,包括,一个更泛化的抽象事物,以及由它而继承得来的一个或多个特化事物。

大多数情况下,会使用一个树型层次结构来组织这些抽象事物,当然,也可以使用更通用的组织方式。


一个泛化/特化层次结构

一个泛化/特化层次关系,最少起着四个主要作用。首先,它提供了一个知识表示形式。在层次结构中,某个较高的、更泛化的层级,表达的是,对于由它的所有特化后代所拥有的通用属性和行为。于是,就可以做出某些声明,例如,“所有的窗口都可以改变大小”,以及,“所有的窗口都可以改变位置”。第二,在层次结构中,那些中间层级,提供了一个有用的词汇表,可用于在开发者之间、开发者和领域专家(那些人对于应用领域的事物狠在行,但并不一定懂得计算机科学)之间交流。这样一个词汇表,能够排除讨论过程中的歧义,因为,它的那些术语标识了特定的、明确定义的概念。第三,对于这个层次结构,可通过在任意级别加入新的特化的方式来进行扩展。这些添加动作,比较容易进行,因为,它们是在一个已有的框架中进行的,其中已经定义了一些、甚至是狠多相关的属性和行为。例如,要想添加一个特化过的条目(Item),就不需要重新定义窗口(Window)和条目(Item)具有的所有那些属性和行为,因为,这些东西,是即将添加的那个特化条目(Item)的一些较通用的属性。第四,可以轻易地向适当的特化子集中添加新的属性和行为:任何一个新的、可能被所有的条目(Items)需要的属性或行为,都可以添加到Item 中去。然后,这些新添加的属性或行为,就会自动成为所有特化条目(Items)的一部分,但不会成为别的任何事物的一部分。


通用


泛型
,是一种部分泛化手段, 它通常被称为泛型、模板、参数类或泛型类。此处 ,称它为“部分的”泛化,是因为, 在这种泛化中,最少有某些属性 是由其它那些并非是此泛化的成员( 也就是说,在这个泛化中找不到 )的属性来表达的。例如, 一个泛型的冒泡排序 (BubbleSort)类, 它能够准确地实现冒泡排序 的排序过程。 在冒泡排序中,一个基本的步骤即是,进行比较,例如 if ( A < B )... ,其中 A B 是两个等待排序的元素。 在不知道"<"操作符的确切意义的情况下,仍然可以完美地实现这个排序过程。 在不同的使用场景中,"<"操作符可能会解释成不同意义。例如 :在对整数进行冒泡排序的过程中,就直接使用数值式的解释就可以了; 在对字符串进行冒泡排序的过程中,就按照字典顺序来解释; 在对用户定义的类型进行冒泡排序的过程中, 就会按照用户定义的方式来进行解释。

泛型,可按如下文字来定义:

泛型

一个命名的泛化方式,由其它未指定的、由参数来确定的抽象来表达。

一个泛型类,可以形象在画成带有一个“洞”的类。此处的这个洞,称作该个泛型类的参数,即代表着此个泛化中的缺失的那一部分。填上这个洞,就使得整个泛化完整了。之后,这个完整的泛化,即成为一个完整形态的类,可用来创建对象实例。无法直接利用泛型类来创建对象,因为,泛型类本身是不完整的。


带有一个参数的泛型类

泛型类中,可以有多于一个的洞或者参数。有一种常见的数据组织形式中会出现这种情况,那就是,一个通用的查找表(LookupTable),它维护着一个值("value")与用来唯一标识它的那个键("key")之间的关联关系。LookupTable 的基本操作就是,在指定一个键的情况下,给出一个值。这种形式的表(Tables),可用来维护键值对( (key, value) )关联关系,例如,名字-电话号码( (name, phone number) ),账号-余额( (account number, balance) ),或,名字-账号( (name, account number) )。下图展示了这种形式的一个泛型类。


带有两个参数的泛型类

在这个泛型类中,那两个参数代表着特定种类的键和值,在这个示例中,分别是某个人的名字和电话号码。这样的一个参数组合,就造出了一个电话本(PhoneBook)。使用其它的键与值组合,就能够造出其它用途的查找表(LookupTables)。


多态


多态,是一种用来将算法通用化的手段。在这种通用性形式中,允许算法以统一的方式来对不同类(classes)的对象进行操作,前提是,该算法只会使用由那些不同的类所共有的属性。任何一种拥有这种共有属性的对象,都可以被这个算法操作。在某些面向对象的编程语言中,要求编译器能够在编译期间进行验证,以确认某个对象是否拥有这些必须的共有属性。而其它的语言,则允许这种验证推迟到运行时再进行,这种,就面临着一个风险,如果在运行过程中,发现该对象并不具有其中的某个必须的共有属性的话,则会引起运行时错误。

多态可定义如下:

多态

能够有不同类的对象进行操作,并仅仅使用它们的共有属性,而不理会它们的具体类。


多态的意义,在它的两个词根中反映出来了: 多( poly )表示“狠多”("many")或“多个”("several"),态( morph )表示“形状”("shape")、“形式”("form")或“外观”("appearance")。因此,多态( polymorphism ),表示的是,具有多种形状或形式的事物。在面向对象编程语言中,“形状、形式或外观”,表达的即是,某个对象的接口或属性。“多”(),暗示着,那些对象,它们的接口或属性是不相同的,或者是有所区别的。此处的难点在于,如何以一种统一的形式来对这些不相同的对象做操作。

人们会在多种活动中使用多态。举个例子,收银员负责计算出顾客所买商品的总额。每个商品,都带有一个条码,收银员只需将条码送到条码扫描器前面即可。条码扫描器会读取条码中包含的标识信息,向商品数据库查询,再将信息报告给收银台计算金额。此处,收银员的操作,就是遵守一个通用的算法,可描述如下:

while ( more storeItems ) {

pick up next storeItem;

scan storeItem;

put scanned storeItem in bag;

};

这个算法中,并不会在意该商店中出售的商品究竟有多少钟;它只会将那些物品都当成“货”("storeItem")看待。对于货(storeItem),只有一个要求,那就是,它必须带有一个条码,使得它能够被扫描。任何一个带有此种条码的商品,都能够由该收银员处理。反之,任何一个不带条码的事物,都无法由此收银员处理。在这个例子中,编译期检查,就相当于,在将商品放到货架上时(也就是说,当商店正在被“编程”时),检查商品上是否有条码。运行时检查,就相当于,由收银员检查商品上是否有条码,如果没有条码,则给老板打电话,报告这件事。在日常生活中,有狠多类似的示例, 人们在这些活动中以一种多态的方式来动作:将书摆到图书馆的架子上;驾驶不同类型的车子;使用不同类型的电脑;等等。

利用多态,可创建出可扩展的软件。新的、具有必要的共有属性的类,都能够被多态算法所处理:算法无需做任何改动,就能够适应新的那些类。对于收银员算法来说,也是如此。当新的种类的商品被添加到商店的库存中去的时候,商店的收银员无需做任何额外的训练(重新编程)。

在面向对象的系统中,需要用一种名为 动态绑定 的机制来实现多态。在这个上下文中,这个术语, 绑定 ,表示的是,将多态算法中的某个实现与接收到调用的对象中的某个方法的代码关联起来。由于多态算法本身并不知道接收调用的对象具体的类,所以,绑定必须是动态完成的,因为,相同的调用可能会在不同的执行场景中根据具体提供的对象而被绑定到不同的方法上去。下图展示了动态绑定过程。


动态绑定

在这个示例中,多态算法调用了F()方法,它是由多个类所共有的一个属性。算法并不知道这次调用具体会被导向哪个类型的对象,它不知道该对象是X 类还是Y 类的对象。动态绑定机制会确定该对象的类型,并且将调用映射到正确的方法上去,如果该对象是类X 的对象,则映射到类X 的方法,如果是类Y 的对象,则映射到类Y 的方法。


模式


模式,是将针对某个常见问题的解决方法变得通用化。模式,是一种泛化手段,为什么呢,因为,模式并不直接给出能够用于解决特定问题的立即可用的解决方案,而是给出针对那些具有特定特性的问题的解决方案的一般形式。模式的使用者必须将该模式适配到自己手头的场景,并提供出模式中尚未给出的 那些细节。人们相信,经验丰富的设计者,会理解(甚至是到达了某个直觉的或下意识的程度)全套的模式,并且,能够判断出,对于当前的问题,可以使用之前已经在一个或多个问题中使用过的哪个模式来解决。而那些新手设计者呢,由于缺乏从之前设计中积累的经验,所以,不得不将她/他们遇到的每个新问题当成从未被别人解决过的问题来对待,于是就重复发明之前世代的设计者已经创造好的东西。

模式 ,跨越多个级别的规模,并且具有狠多规则。 在计算机科学中, 大规模的模式通常被称为 架构 模型 这种大规模模式的示例包括: 客户端-服务器模型 分层架构 ;和 微内核架构 小规模的模式通常被称为 计划 习惯用法 ,因为 ,它们代表着对于编程语言结构 的一种常见用法。对于 这种规模的模式,其中一个示例是,“带计数器的可提前结束的循环”计划, 它可被用来扫描一个固定长度的数组,并在数组末尾结束或者在满足某个搜索条件的情况下提前结束。 在计划中,会指定初始条件、循环结构中各个元素的组织方式、以及终止条件。 该计划,可使用图像或伪代码来表示,使得用户可将它映射到不同的编程语言中去。模式 ,也经常以其它规则的形式出现,正如 设计模式 这本书的作者们指出的那样, 他们指明 了模式在建筑和文学活动中的作用。

模式,定义如下:

模式

一个命名的泛化手段,描述了,针对某个常见的设计问题的某个解决方案中的元素和关系。

模式中,包含四个必要部分:名字;问题;解决方案;以及副作用。下面以一个简单的客户端-服务器模式来展示这四个部分。模式的名字,用于简短准确地描述该模式的主要特点。在这个示例中, 客户端-服务器 这个名字就狠合适。模式的问题部分,描述的是,该模式适用于什么场景(也就是说,这个模式是用来解决什么问题的)。客户端-服务器问题,主要的目标在于,以一种松耦合的方式向多个潜在的客户提供服务。解决方案,描述的是,方案中包含的元素、这些元素各自的职责、以及这些元素是如何组织起来以解决问题的。客户端-服务器模式的各个元素,在下图中以图像方式展示。


客户端-服务器模式


客户端-服务器模式包含五个元素。客户端的职责是,生成一个请求,请求被发送到服务器,服务器会对应地执行服务动作并以响应内容的形式做出回复。在客户端和服务器之间传递请求和回复的职责,是由一个中间元素来承担的,它被称为连接。客户端和服务器都只是直接与连接做交互(互相之间是间接交互)。各个元素之间的协作过程,定义为如下事件序列:客户端生成请求;请求被传送到服务器;服务器生成回复;回复被传送到客户端。

注意,这个模式中,并未指定提供的服务的具体类型,它可以是一个名字解析服务、时间服务、位置服务、文件服务、安全服务或别的什么服务。同时,模式中也并未指定,要如何实现这个连接。该连接可以是:连接着同一个进程中的两个执行过程的某个内存缓冲区;连接着同一个机器上的两个不同进程的某个内存缓冲区;不同机器上两个进程之间的某个网络连接。尽管这些细节会随情况而变化,但是模式本身不变。

模式还会说明,使用该模式会带来的正面及负面后果。某些正面后果包括:客户端和服务器能够在不同的机器上实现,使得各自能够利用本机上特定的硬件或软件资源;客户端和服务器可能完全地或者狠大程度上地不知道且不关心对方的实际位置;服务器可同时为狠多客户端提供服务。另外,客户端-服务器模式,有两个负面后果:如果请求或回复被丢失了,或者服务器崩溃了,那么可能会导致客户端的运行过程挂起;客户端无法控制服务器端的服务 - 它只能请求使用这种服务。

在面向对象设计中,模式,是通过类和对象的方式来表达的。模式中的元素是以类来代表的。元素之间的关系,是通过关联(association)、聚合(aggregation)和/或层次结构(hierarchy)来定义的。职责,是由每个类的行为来说明的。协作方式,是由类之间的关联关系,也就是交互方式来说明的。

模式,是另一种形式的泛化;与泛型类似的是,它也是一个部分泛化手段,省掉了某些细节。然而,泛型,最少会产生出不完整的代码,而模式呢,根本就不需要用代码来表达。在模式中,可能也会使用层次关系,但是,在模式中并不具有泛化/特化的视角。

未知美人

未知美人

Your opinions
Your name:Email:Website url:Opinion content:
- no title specified

HxLauncher: Launch Android applications by voice commands