抽象的进步外文翻译资料

 2022-07-30 20:58:14

Excerpt from 《Thinking in Java》

The progress of abstraction

All programming languages provide abstractions. It can be argued that the complexity of the problems yoursquo;re able to solve is directly related to the kind and quality of abstraction. By “kind” I mean, “What is it that you are abstracting?” Assembly language is a small abstraction of the underlying machine. Many so-called “imperative” languages that followed (such as FORTRAN, BASIC, and C) were abstractions of assembly language. These languages are big improvements over assembly language, but their primary abstraction still requires you to think in terms of the structure of the computer rather than the structure of the problem you are trying to solve. The programmer must establish the association between the machine model (in the “solution space,” which is the place where yoursquo;re implementing that solution, such as a computer) and the model of the problem that is actually being solved (in the“problem space,” which is the place where the problem exists, such as a business). The effort required to perform this mapping, and the fact that it is extrinsic to the programming language, produces programs that are difficult to write and expensive to maintain, and as a side effect created the entire “programming methods” industry.

The alternative to modeling the machine is to model the problem yoursquo;re trying to solve. Early languages such as LISP and APL chose particular views of the world (“All problems are ultimately lists” or “All problems are algorithmic,” respectively). Prolog casts all problems into chains of decisions. Languages have been created for constraint-based programming and for programming exclusively by manipulating graphical symbols. (The latter proved to be too restrictive.) Each of these approaches may be a good solution to the particular class of problem theyrsquo;re designed to solve, but when you step outside of that domain they become awkward.

The object-oriented approach goes a step further by providing tools for the programmer to represent elements in the problem space. This representation is general enough that the programmer is not constrained to any particular type of problem. We refer to the elements in the problem space and their representations in the solution space as “objects.” (You will also need other objects that donrsquo;t have problem-space analogs.) The idea is that the program is allowed to adapt itself to the lingo of the problem by adding new types of objects, so when you read the code describing the solution, yoursquo;re reading words that also express the problem. This is a more flexible and powerful language abstraction than what wersquo;ve had before.1 Thus, OOP allows you to describe the problem in terms of the problem, rather than in terms of the computer where the solution will run. Therersquo;s still a connection back to the computer: Each object looks quite a bit like a little computer—it has a state, and it has operations that you can ask it to perform. However, this doesnrsquo;t seem like such a bad analogy to objects in the real world—they all have characteristics and behaviors.

Alan Kay summarized five basic characteristics of Smalltalk, the first successful object-oriented language and one of the languages upon which Java is based. These characteristics represent a pure approach to object-oriented programming:

1. Everything is an object. Think of an object as a fancy variable; it stores data, but you can “make requests” to that object, asking it to perform operations on itself. In theory, you can take any conceptual component in the problem yoursquo;re trying to solve (dogs, buildings, services, etc.) and represent it as an object in your program.

2. A program is a bunch of objects telling each other what to do by sending messages. To make a request of an object, you “send a message” to that object. More concretely, you can think of a message as a request to call a method that belongs to a particular object.

3. Each object has its own memory made up of other objects. Put another way, you create a new kind of object by making a package containing existing objects. Thus, you can build complexity into a program while hiding it behind the simplicity of objects.

4. Every object has a type. Using the parlance, each object is an instance of a class, in which “class” is synonymous with “type.” The most important distinguishing characteristic of a class is “What messages can you send to it?”

5. All objects of a particular type can receive the same messages. This is actually a loaded statement, as you will see later. Because an object of type “circle” is also an object of type “shape,” a circle is guaranteed to accept shape messages. This means you can write code that talks to shapes and automatically handle anything that fits the description of a shape. This substitutability is one of the powerful concepts in OOP.

Booch offers an even more succinct description of an object:

An object has state, behavior and identity.

This means that an object can have internal data (which gives it state), methods (to produce behavior), and each object can be uniquely distinguished from every other object—to put this in a concrete sense, each object has a unique address in memory.

An object has an interface

Aristotle was probably the first to begin a careful study of the concept of type; he spoke of “the class of fishes and the class of birds.” The idea that all objects, while being unique, are also part of a class of objects that have characteristics and behaviors in common was used directly in the first object-oriented language, Simula-67, with its fundamental keyword class that introduces a new type into a program.

Simula, as its name implies, was created for developing simulations such as the classic “bank teller problem.” In this, you have num

全文共25069字,剩余内容已隐藏,支付完成后下载完整资料


节选自《Thinking in Java》

抽象的进步

所有编程语言的最终目的都是提供一种“抽象”方法。一种较有争议的说法是:解决问题的复杂程度直接取 决于抽象的种类及质量。这儿的“种类”是指准备对什么进行“抽象”?汇编语言是对基础机器的少量抽象。后来的许多“命令式”语言(如FORTRAN,BASIC和C)是对汇编语言的一种抽象与汇编语言相比这些语言已有了长足的进步,但它们的抽象原理依然要求我们着重考虑计算机的结构,而非考虑问题本身的结 构。在机器模型(位于“方案空间”)与实际解决的问题模型(位于“问题空间”)之间,程序员必须建立 起一种联系。这个过程要求人们付出较大的精力,而且由于它脱离了编程语言本身的范围,造成程序代码 难编写,而且要花较大的代价进行维护。由此造成的副作用便是一门完善的“编程方法”学科。

为机器建模的另一个方法是为要解决的问题制作模型。对一些早期语言来说,如LISP 和 APL,它们的做法是“从不同的角度观察世界”——“所有问题都归纳为列表”或“所有问题都归纳为算法”。PROLOG则将所有问题都归纳为决策链。对于这些语言,我们认为它们一部分是面向基于“强制”的编程,另一部分则是专为 处理图形符号设计的。每种方法都有自己特殊的用途,适合解决某一类的问题。但只要超出了它们力所能及的范围,就会显得非常笨拙。

面向对象的程序设计在此基础上则跨出了一大步,程序员可利用一些工具表达问题空间内的元素。由于这种 表达非常普遍,所以不必受限于特定类型的问题。我们将问题空间中的元素以及它们在方案空间的表示物称作“对象”(Object)。当然,还有一些在问题空间没有对应体的其他对象。通过添加新的对象类型,程序 可进行灵活的调整,以便与特定的问题配合。所以在阅读方案的描述代码时,会读到对问题进行表达的话 语。与我们以前见过的相比,这无疑是一种更加灵活、更加强大的语言抽象方法。总之,OOP允许我们根据 问题来描述问题,而不是根据方案。然而,仍有一个联系途径回到计算机。每个对象都类似一台小计算机; 它们有自己的状态,而且可要求它们进行特定的操作。与现实世界的“对象”或者“物体”相比,编程“对 象”与它们也存在共通的地方:它们都有自己的特征和行为。

Alan Kay总结了Smalltalk的五大基本特征。这是第一种成功的面向对象程序设计语言,也是Java 的基础 语言。通过这些特征,我们可理解“纯粹”的面向对象程序设计方法是什么样的:

(1) 所有东西都是对象。可将对象想象成一种新型变量;它保存着数据,但可要求它对自身进行操作。理论 上讲,可从要解决的问题身上提出所有概念性的组件,然后在程序中将其表达为一个对象。

(2) 程序是一大堆对象的组合;通过消息传递,各对象知道自己该做些什么。为了向对象发出请求,需向那个对象“发送一条消息”。更具体地讲,可将消息想象为一个调用请求,它调用的是从属于目标对象的一个 子例程或函数。

(3) 每个对象都有自己的存储空间,可容纳其他对象。或者说,通过封装现有对象,可制作出新型对象。所 以,尽管对象的概念非常简单,但在程序中却可达到任意高的复杂程度。

(4) 每个对象都有一种类型。根据语法,每个对象都是某个“类”的一个“实例”。其中,“类”(Class) 是“类型”(Type)的同义词。一个类最重要的特征就是“能将什么消息发给它?”。

(5) 同一类所有对象都能接收相同的消息。这实际是别有含义的一种说法,大家不久便能理解。由于类型为 “圆”(Circle)的一个对象也属于类型为“形状”(Shape)的一个对象,所以一个圆完全能接收形状消 息。这意味着可让程序代码统一指挥“形状”,令其自动控制所有符合“形状”描述的对象,其中自然包括“圆”。这一特性称为对象的“可替换性”,是OOP最重要的概念之一

Booch提供了一个更为简洁的描述对象:对象具有状态、行为和身份。

这意味着一个对象可以有内部数据(给出它的状态),方法(产生行为),并且每个对象可以唯一地区别于其他对象,把它具体化,每个对象在内存中有唯一的地址。

对象的接口

亚里士多德或许是认真研究“类型”概念的第一人,他曾谈及“鱼类和鸟类”的问题。所有对象,尽管各有特色,但是都属于某一系列对象的一部分,这些对象具有通用的特征和行为在面向对象语言Simula-67 中,第一次用到了class 这个关键字,它为程序引入了一个全新的类型。

Simula是一个很好的例子。正如这个名字所暗示的,它的作用是“模拟”(Simulate)象“银行出纳员”这样的经典问题。在这个例子里,我们有一系列出纳员、客户、帐号以及交易等,这些都是相同的,除了程序执行过程中的状态被分组到“对象类”中,这就是关键字类的来源。创建抽象数据类型(类)是面向对象编程中的一个基本概念。抽象数据类型几乎完全类似于内置类型:您可以创建一个类型的变量(称为面向对象语言中的对象或实例)并操纵这些变量(称为发送消息或请求;您发送消息并且对象计算出该怎么办)。与此同时,每个成员都有 自己的状态;每个帐号都有不同的余额;每名出纳都有一个名字。所以在计算机程序中,能用独一无二的实 体分别表示出纳员、客户、帐号以及交易。这个实体便是“对象”,而且每个对象都隶属一个特定的 “类”,那个类具有自己的通用特征与行为。

因此,在面向对象的程序设计中,尽管我们真正要做的是新建各种各样的数据“类型”(Type),但几乎所 有面向对象的程序设计语言都采用了“class”关键字。当您看到“type”这个字的时候,请同时想到 “class”;反之亦然。

由于类描述了具有相同特征(数据元素)和行为(功能)的一组对象,所以类实际上是一种数据类型,因为就好像浮点数也具有一组特征和行为。不同之处在于,程序员定义了一个类来适应问题,而不是强制使用旨在表示机器中存储单元的现有数据类型。您可以通过添加特定于您的需求的新数据类型来扩展编程语言。编程系统欢迎新课程,并给予它们对内置类型的所有关心和类型检查。

面向对象的方法不限于构建模拟。无论您是否同意任何程序都是您正在设计的系统的模拟,使用OOP技术可以轻松地将一大堆问题简化为一个简单的解决方案。

建好一个类后,可根据情况生成许多对象。随后,可将那些对象作为要解决问题中存在的元素进行处理。事 实上,当我们进行面向对象的程序设计时,面临的最大一项挑战性就是:如何在“问题空间”(问题实际存 在的地方)的元素与“方案空间”(对实际问题进行建模的地方,如计算机)的元素之间建立理想的“一对 一”对应或映射关系

如何利用对象完成真正有用的工作呢?必须有一种办法能向对象发出请求,令其做一些实际的事情,比如完成一次交易、在屏幕上画一些东西或者打开一个开关等等。每个对象仅能接受特定的请求。我们向对象发出的请求是通过它的“接口”(Interface)定义的,对象的“类型”或“类”则规定了它的接口形式。“类型”与“接口”的等价或对应关系是面向对象程序设计的基础。

为方便讨论,先对这一领域的从业人员作一下分类,涉足面向对象的编程:“类创建者”(创建新数据类型的人)以及“客户程序员”(在自己的应用程序中采用现成数据类型的人)。对客户程序员来讲,最主要的目标就是收集一个充斥着各种类的编程“工具 箱”,以便快速开发符合自己要求的应用。而对类创建者来说,他们的目标则是从头构建一个类,只向客户 程序员开放有必要开放的东西(接口),其他所有细节都隐藏起来。为什么要这样做?隐藏之后,客户程序员就不能接触和改变那些细节,所以原创者不用担心自己的作品会受到非法修改,可确保它们不会对其他人造成影响。隐藏部分通常表示一个对象的内部,它很容易被一个粗心的或者不知情的客户程序员破坏,因此隐藏实现可以减少程序错误。

对于任何关系,重要一点是让牵连到的所有成员都遵守相同的规则。创建一个库时,相当于同客户程序员建立了一种关系。对方也是程序员,但他们的目标是组合出一个特定的应用(程序),或者用您的库构建一个更大的库。若任何人都能使用一个类的所有成员那么客户程序员可对那个类做任何事情,没有办法强制他们遵守任何约束。即便非常不愿客户程序员直接操作类内包含的一些成员,但倘若未进行访问控制,就没有办法阻止这一情况的发生——所有东西都会暴露无遗

第一个原因是防止程序员接触他们不该接触的东西——通常是 内部数据类型的设计思想。若只是为了解决特定的问题,用户只需操作接口即可,毋需明白这些信息。我们 向用户提供的实际是一种服务,因为他们很容易就可看出哪些对自己非常重要,以及哪些可忽略不计。

进行访问控制的第二个原因是允许库设计人员修改内部结构,不用担心它会对客户程序员造成什么影响。例如,我们最开始可能设计了一个形式简单的类,以便简化开发。以后又决定进行改写,使其更快地运行。若接口与实现方法早已隔离开,并分别受到保护,就可放心做到这一点,只要求用户重新链接一下即可。

实现方案的隐藏

Java使用三个显式关键字来设置类的边界:公共、私有和受保护。这些访问指示符决定谁可以使用下面的定义。“public”(公共)意味着后续的定义任何人均可使 用。而在另一方面,“private”(私有)意味着除您自己、类型的创建者以及那个类型的内部函数成员,其 他任何人都不能访问后续的定义信息。private在您与客户程序员之间竖起了一堵墙。若有人试图访问私有成员,就会得到一个编译期错误。“friendly”(友好的)涉及“包装”或“封装”(Package)的概念——即Java 用来构建库的方法。若某样东西是“友好的”,意味着它只能在这个包装的范围内使用(所以这一访 问级别有时也叫作“包装访问”)。“protected”(受保护的)与“private”相似,只是一个继承的类可 访问受保护的成员,但不能访问私有成员。继承的问题不久就要谈到。

Java也有一个“默认的”访问,如果你不使用前面提到过的专门设置,它就会发挥作用。这通常称为包访问,因为类可以访问同一个包中的其他类的成员(库组件),但是在包的外部,这些成员似乎是私有的。

方案的重复使用

创建并测试好一个类后,它应(从理想的角度)代表一个有用的代码单位。但并不象许多人希望的那样,这 种重复使用的能力并不容易实现;它要求较多的经验以及洞察力,这样才能设计出一个好的方案,才有可能 重复使用,但是一旦你有了这样的设计,它就会被重新使用。许多人认为代码或设计方案的重复使用是面向对象的程序设计提供的最伟大的一种杠杆。

为重复使用一个类,最简单的办法是仅直接使用那个类的对象。但同时也能将那个类的一个对象置入一个新类。我们把这叫作“创建一个成员对象”。新类可由任意数量和类型的其他对象构成。无论如何,只要新类达到了设计要求即可。这个概念叫作“组织”——在现有类的基础上组织一个新类。有时,我们也将组织称作“包含”关系,比如“一辆车包含了一个变速箱”。

对象的组织具有极大的灵活性。新类的“成员对象”通常设为“私有”(Private),使用这个类的客户程序员不能访问它们。这样一来,我们可在不干扰客户代码的前提下,从容地修改那些成员。也可以在“运行 期”更改成员,这进一步增大了灵活性。后面要讲到的“继承”并不具备这种灵活性,因为编译器必须对通过继承创建的类加以限制

由于继承的重要性,所以在面向对象的程序设计中,它经常被重点强调。作为新加入这一领域的程序员,或许早已先入为主地认为“继承应当随处可见”。沿这种思路产生的设计将是非常笨拙的,会大大增加程序的复杂程度。相反,新建类的时候,首先应考虑“组织”对象;这样做显得更加简单和灵活。利用对象的组织,我们的设计可保持清爽。一旦需要用到继承,就会明显意识到这一点。

继承

就其本身来说,对象的概念可为我们带来极大的便利。它在概念上允许我们将各式各样数据和功能封装到一 起。这样便可恰当表达“问题空间”的概念,不用刻意遵照基础机器的表达方式。在程序设计语言中,这些 概念则反映为具体的数据类型(使用class 关键字)。

然而,为了创建一个类,然后被迫创建一个可能具有类似功能的全新的类,这似乎很可惜。如果我们可以使用现有的类,克隆它,然后对克隆进行添加和修改,那就更好了.。在继承过程中,若原始类(正式名称叫作基础类、超类或父类)发生了变化,修改过的“克隆”类(正式名称叫作继承类或者子类)也会反映出这种变化。

类型不仅仅描述对象集合上的约束;它还与其他类型有关系。两种类型可以具有相同的特征和行为,但是一种类型可能包含更多的特性,也可以处理更多的消息(或者以不同的方式处理它们)。继承通过使用基础类型与衍生类型的概念来表示类型之间的相似性。基础类型包含从它衍生的类型中共享的所有特征和行为。创建一个基本类型来表示系统中一些对象的核心思想。从基础类型,可以衍生其他类型来表达这个核心可以实现的不同方式。

对象的创建和存在时间

处理对象的一个关键问题是它们的创建和销毁方式。每个对象都需要资源,尤其是内存,以便存在。当不再需要对象时,必须清理这些资源,以便这些资源被释放以便重用。在简单的编程场景中,如何清理对象的问题似乎并不太具有挑战性:你创建对象,只要需要,就使用它,然后它就应该被销毁。然而,遇到更复杂的情况并不难。

举个例子来说,假设我们要设计一套系统,用它管理一个机场的空中交通(同样的模型也可能适于管理一个 仓库的货柜、或者一套影带出租系统、或者宠物店的宠物房。这初看似乎十分简单:构造一个集合用来容纳飞机,然后创建一架新飞机,将其置入集合。对进入空中交通管制区的所有飞机都如此处理。至于清除,在一架飞机离开这个区域的时候把它简单地删去即可。

但事情并没有这么简单,可能还需要另一套系统来记录与飞机有关的数据。当然,和控制器的主要功能不同,这些数据的重要性可能一开始并不显露出来。例如,这条记录反映的可能是离开机场的所有小飞机的飞行计划。所以我们得到了由小飞机组成的另一个集合。一旦创建了一个飞机对

全文共8646字,剩余内容已隐藏,支付完成后下载完整资料


资料编号:[143019],资料为PDF文档或Word文档,PDF文档可免费转换为Word

原文和译文剩余内容已隐藏,您需要先支付 30元 才能查看原文和译文全部内容!立即支付

以上是毕业论文外文翻译,课题毕业论文、任务书、文献综述、开题报告、程序设计、图纸设计等资料可联系客服协助查找。