俄罗斯方块游戏JAVA程序设计外文翻译资料

 2022-09-19 10:09

Introduction To Objects

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 modeling that problem, 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). 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 is 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. 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.

1.2 An object has an interface

Aristotle was probably the first to begin a careful study of the conce

剩余内容已隐藏,支付完成后下载完整资料


对象导论

1.1 抽象的进步

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

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

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

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

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

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

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

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

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

一些语言设计者认为面向对象的程序设计本身并不足以方便解决所有形式的程序问题,提倡将不同的方法组合成“多形程序设计语言”。

1.2 对象的接口

亚里士多德或许是认真研究“类型”概念的第一人,他曾谈及“鱼类和鸟类”的问题。在世界首例面向对象语言Simula-67中,第一次用到了这样的一个概念:

所有对象——尽管各有特色——都属于某一系列对象的一部分,这些对象具有通用的特征和行为。在Simula-67中,首次用到了class这个关键字,它为程序引入了一个全新的类型(clas和type通常可互换使用)。

Simula是一个很好的例子。正如这个名字所暗示的,它的作用是“模拟”(Simulate)象“银行出纳员”这样的经典问题。在这个例子里,我们有一系列出纳员、客户、帐号以及交易等。每类成员(元素)都具有一些通用的特征:每个帐号都有一定的余额;每名出纳都能接收客户的存款;等等。与此同时,每个成员都有自己的状态;每个帐号都有不同的余额;每名出纳都有一个名字。所以在计算机程序中,能用独一无二的实体分别表示出纳员、客户、帐号以及交易。这个实体便是“对象”,而且每个对象都隶属一个特定的“类”,那个类具有自己的通用特征与行为。

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

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

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

下面让我们以电灯泡为例:

Light

On()

Off()

Light lt = new Light();

lt.on();

在这个例子中,类型/类的名称是Light,可向Light对象发出的请求包括包括打开(on)、关闭(off)、变得更明亮(brighten)或者变得更暗淡(dim)。通过简单地声明一个名字(lt),我们为Light对象创建了一个“句柄”。然后用new关键字新建类型为Light的一个对象。再用等号将其赋给句柄。为了向对象发送一条消息,我们列出句柄名(lt),再用一个句点符号(.)把它同消息名称(on)连接起来。从中可以看出,使用一些预先定义好的类时,我们在程序里采用的代码是非常简单和直观的。

1.3 对象会提供服务

当你开发一个程序或者分析一个程序设计时,理解对象的最佳的方式是把他们当作“服务提供者”。程序本身会为用户提供服务,而它通过使用其它对象所提供的服务来完成这个工作。你的任务是制作(或者在更理想的情况下,从现有的代码库中找出)一组能为解决问题提供最佳服务的对象。

这么做的第一步是问“如果我可以像变魔术那样把东西从帽子里拿出来,我该拿出些什么东西,哪些对象能立即帮我解决问题?”举例来说,假设你要创建一个簿记程序。可能你会想应该有一些保存预设的输入界面的对象,一组进行簿记计算的对象,以及一个能在各种打印机上打印支票和发票的对象。有些对象或许已经有了,但是那些还没有的应该是什么样的呢?它们应该提供哪种服务,还有它们要完成任务的话,又该用哪些对象呢?如果你不断分析下去,最终你会发现,不是“那个对象写起来很容易”就是“那个对象已经有了。”这是将问题分解成一组对象的一个合理的方法。

将对象视作为服务的提供者还有一个额外的优点:能提高对象的内聚星。内聚性高是高质量的软件设计一个基本要求:就是说软件的各种组将应该能很好的“组装在一起”

设计对象时常犯的一个错误就是,往对象里塞了太多的功能。举例来说,设计支票打印模块的时候,你也许会决定设计一个能通晓所有排格式和打印工作细节的对象。很快你就会发现这个任务太艰巨了,或许应该用三个或是更多对象来完成这个工作。第一个对象应该是支票格式的目录册,通过查询这个目录册可以获取得该如何打印支票的信息。第二个对象,或是一组对象,应该是能分辨各种打印机的通用的打印接口。以及使用上述两个对象所提供的服务的,能最终完成任务的第三个对象。由此每个对象都提供一组互补的功能。在一个良好的面向对象的设计中,每个对象都应该只做一件事,并且做好一件事,而不是去做太多的事情。就像这里看到的,这样不仅能发现那些对象因该买(打印机接口对象),而且能设计出今后能复用的对象(支票格式的目录册)。

将对象视作服务的提供者还是一种很了不起的简化工具。它不仅在设计过程中有用,而且还能帮助别人理解你的代码或者复用这个对象—如果它们认同这个对象所提供的服务的话。将对象视作服务的提供者能使对象更容易被用于设计.

1.4实现方案的隐藏

为方便后面的讨论,我们将程序员分为:“类创建者”(创建新数据类型的人)以及“客户端程序员”(在自己的应用程序中采用现成 数据类型的人)。对客户端程序员来讲,最主要的目标就是收集一个充斥着各种类的编程“工具箱”,以便快速开发符合自己要求的应用。

对类创建者来说,他们的目标则是从头构建一个类,只向客户端程序员开放有必要开放的部分,其他所有细节都对其隐藏。为什么要这样做?因为如果加以隐藏,那么客户端程序员便不能访问该部分,这意味着创建者可以任意修改被隐藏的部分而不必担心对其他人造成影响。被隐藏的部分通常是较为敏感的部分,他们很容易被粗心或不知内情的程序员损坏,所以这样的隐藏设置可以减少程序的Bug。

在任何关系中,存在各方所遵守的边界是十分重要的。当创建一个库的同时,与客户端程序员的关系也被建立,他们同样也是程序员,但是他们是使用你的库来构建应用或者更大库的程序员。如果所有类成员对任何人可用,那么客户端程序员就可以对类做任何事情而不受任何约束。即使你希望客户端程序员不对你的类成员做直接操作,这也是不可避免的。所有东西将彻底公开。

因此,访问控制存在的首要原因就是让客户端程序员无法接触他们不应接触的部分——这部分对数据类型的内部操作来说是必须的,但并不是用户用于解决特定问题所需接口所包含的部分。这对客户端程序员来说其实是一项服务,因为他们可以轻易地看出什么是重要的,而哪些可以忽略。

访问控制存在的第二个原因就是允许库设计者改变内部工作方式而不必担心影响到客户端程序员。例如,你可能为了开发工作的简单而用一种简单的方式实现了一种特定类,但稍后你发现你必须改写他以以提升运行速度。如果接口和实现方案可以被清晰地分离并加以保护,这项工作对你来说会轻而易举。

Java用三个关键字在类的内部设立边界:public、private、protected。这些访问指定关键字决定了紧跟其后的元素能够被谁使用。public表示紧随其后的元素对任何人都是可用的。private这个关键字表示除了类型创建者和类型的内部方法之外的任何人都无法访问元素。private就像是你与客户端程序员之间的一堵墙,若果有人试图访问private元素,那么编译时就会得到错误信息。protected关键字功能类似于private,区别仅在于继承的类可以访问protected成员,但是不能访问private成员。

Java还有一种“默认”访问权限,会在未使用访问指定词关键字时发挥作用。这种机制通常被称为“包访问权限”,因为在这种权限下,类可以在访问一个包(库组件)中的其他类成员,但是在包外,这些成员将等同于加上了private。

1.5复用的实现

一旦一个类被创建并测试,那么它就应该(在理想条件下)代表一个有用的单元代码。事实证明,这种复用性并不容易达到我们所期望的水平,设计一个能够复用的对象需要丰富的经验和敏锐的洞察力。但是你一旦有了这种设计,它就能够被复用。代码复用是面向对象程序设计语言最伟大的成就之一。

复用一个类的最简单的方式就是直接使用该类的一个对象,此外也可以将那个类的一个对象置于某个新类中。我们称之为“创建一个成员对象”。新的类可以由任意数量、任意类型的其他对象以任意方式组成以实现你想要的功能。因为正在使用新的类,所以这种概念被称为组合(composition),如果组合是动态发生的则被称之为聚合(aggregation)。组合经常被视为“拥有”关系,就如同常说的“汽车拥有引擎”一样。

组合带来了极大的灵活性。新类的成员对象通常都被声明作private,这使得使用新类的客户端程序员无法访问它们。这也允许你可以在不干扰现有客户端代码的情况下修改这些成员。也可以在运行时修改这些成员对象,以实现动态修改程序。下面讨论的继承并不具有这样的灵活性,这是因为编译器必须通过对继承创建的类加以限制。

由于继承在面向对象的的程序设计中如此重要,所以它经常被高度重视,以至于很多新手程序员形成了“处处都在使用继承”的印象,这会导致过于复杂和低下的可用性。是机场,在创建新类时,应首先考虑组合,因为它更加简单灵活

1.6继承

对象这种观念,本身就是十分方便

剩余内容已隐藏,支付完成后下载完整资料


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

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

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