分享
 
 
 

面向对象软件构造(第2版)-第2章 面向对象的标准

王朝other·作者佚名  2006-02-01
窄屏简体版  字體: |||超大  

In the previous chapter we explored the goals of the object-oriented method. As a preparation for parts B and C, in which we will discover the technical details of the method, it is useful to take a quick but wide glance at the key aspects of object-oriented development. Such is the aim of this chapter.

在前一章中,我们探索了面向对象方法的目标.作为B和C部分的预备部分,我们将研究方法上的技术细节,并在面向对象开发的关键方面,做有效的快速而广泛的浏览.这就是本章的目标.

One of the benefits will be to obtain a concise memento of what makes a system object-oriented. This expression has nowadays become so indiscriminately used that we need a list of precise properties under which we can assess any method, language or tool that its proponents claim to be O-O.

好处之一是从构造一个面向对象系统中获得一个清晰简洁的佳作.这种说法时下已经变得如此随意地使用,以致于我们需要一系列精确的属性使我们能评估其支持者宣称是OO的任何方法,语言或工具.

This chapter limits its explanations to a bare minimum, so if this is your first reading you cannot expect to understand in detail all the criteria listed; explaining them is the task of the rest of the book. Consider this discussion a preview — not the real movie, just a trailer.

本章对所有的解释都限制在尽可能小的范围内,因此如果您是第一次阅读,不要期望能理解列出的所有标准的细节; 解释它们是其它章节的任务.把本次讨论当作是一个预览—这不是真正的电影,只是一个预告片.

Actually a warning is in order because unlike any good trailer this chapter is also what film buffs call a spoiler — it gives away some of the plot early. As such it breaks the step-by-step progression of this book, especially part B, which patiently builds the case for object technology by looking at issue after issue before deducing and justifying the solutions. If you like the idea of reading a broad overview before getting into more depth, this chapter is for you. But if you prefer not to spoil the pleasure of seeing the problems unfold and of discovering the solutions one by one, then you should simply skip it. You will not need to have read it to understand subsequent chapters.

实际上预告是恰当的,因为和一些精美的预告片不同,这章也是影迷称之为破坏者的部分—它早早的就泄露了电影情节.同样地它打破了本书的按部就班的步骤,尤其是B部份,在推论和验证解决方案之前,通过浏览一个又一个的议题,耐心地为对象技术构建案例.如果您喜欢在进入更深一步之前先了解主要的概观,这章就适合您.但是如果您喜欢逐步发现问题并一个接一个的得到解决方案,不喜欢破坏这种乐趣,那么您仅仅跳过它就可以了.您并不需要为了理解后面的章节而读它.

2.1 ON THE CRITERIA

2.1 标准

Let us first examine the choice of criteria for assessing objectness.

让我们先来调查评估对象的选择标准.

How dogmatic do we need to be?

我们需要什么样的独断?

The list presented below includes all the facilities which I believe to be essential for the production of quality software using the object-oriented method. It is ambitious and may appear uncompromising or even dogmatic. What conclusion does this imply for an environment which satisfies some but not all of these conditions? Should one just reject such a half-hearted O-O environment as totally inadequate?

下面描述的列表中包括了所有的技巧,我相信这些技巧对使用面向对象方法的软件品质是必要的.它富有挑战性而且显得坚决,更甚至有些独断.对于一个只有部分但不是所有的条件都满足的环境,这意味着什么样的结论呢?应该如拒绝完全不是OO的环境那样,拒绝一个半OO的环境吗?

Only you, the reader, can answer this question relative to your own context. Several reasons suggest that some compromises may be necessary:

只有您,读者,能根据您自己的环境来回答这个问题.有几个理由认为某些妥协是必要的:

• “Object-oriented” is not a boolean condition: environment A, although not 100% O-O, may be “more” O-O than environment B; so if external constraints limit your choice to A and B you will have to pick A as the least bad object-oriented choice.

“面向对象”不是一个布尔(boolean)条件:环境A,虽然不是百分之百的OO,但是可能比环境B有”更多的”OO;因此,如果外部的约束限制您只能在A和B中选择,您应该选择A,把面向对象选择的不利因素减小到最少.

• Not everyone will need all of the properties all the time.

不是每一人始终都会需要所有的特性.

• Object orientation may be just one of the factors guiding your search for a software solution, so you may have to balance the criteria given here with other considerations.

面向对象方法只是引导您寻求软件解决方案的因数之一,因此这里,您必须考虑其它的因数来平衡给定的标准.

All this does not change the obvious: to make informed choices, even if practical constraints impose less-than-perfect solutions, you need to know the complete picture, as provided by the list below.

所有的这些并不改变明显的事实: 要作出见多识广的选择,即使实际的约束强迫了较差的解决方案,您也应该了解由下面列表所提供的完整的描述.

Categories

种类

The set of criteria which follows has been divided into three parts:

下面的一组标准分为三个部份:

• Method and language: these two almost indistinguishable aspects cover the thought processes and the notations used to analyze and produce software. Be sure to note that (especially in object technology) the term “language” covers not just the programming language in a strict sense, but also the notations, textual or graphical, used for analysis and design.

方法和语言: 这二个相似的方面包括了思考的过程和用于分析编写软件的符号.注意术语”语言”不但包括一个严格意义上的程序语言,而且涵盖了分析和设计用的符号,本文或图型.

• Implementation and environment: the criteria in this category describe the basic properties of the tools which allow developers to apply object-oriented ideas.

实施和环境: 这一类的标准描述了工具的基本特性,这些工具允许开发者应用面向对象的思想.

• Libraries: object technology relies on the reuse of software components. Criteria in this category cover both the availability of basic libraries and the mechanisms needed to use libraries and produce new ones.

库: 对象技术依赖软件组件的复用.此范畴中的标准包括了两方面:基本库的有效性和使用库生产新库的机制.

This division is convenient but not absolute, as some criteria straddle two or three of the categories. For example the criterion labeled “memory management” has been classified under method and language because a language can support or prevent automatic garbage collection, but it also belongs to the implementation and environment category; the “assertion” criterion similarly includes a requirement for supporting tools.

这些分类合理但并不绝对,一些标准在这几个种类中都存在.例如, “内存管理”的标准可分在方法和语言类,因为一个语言能支持或防止自动垃圾收集,但是它也属于实施和环境种类;”断言”标准也同样地包括了一个支持工具的需求.

2.2 METHOD AND LANGUAGE

2.2 方法和语言

The first set of criteria covers the method and the supporting notation.

第一类标准包括了方法和支持符号.

Seamlessness

无缝化

The object-oriented approach is ambitious: it encompasses the entire software lifecycle.

When examining object-oriented solutions, you should check that the method and language, as well as the supporting tools, apply to analysis and design as well as implementation and maintenance. The language, in particular, should be a vehicle for thought which will help you through all stages of your work.

面向对象的方式具有挑战性:它包含了完整的软件生命周期.当检验面向对象的解决方案时,您应该检查方法和语言,也应该检查适用于分析和设计,实现和维护的支持工具.特别的,语言是一种思维的表达手段,这些思维在您工作的所有阶段中都将帮助您.

The result is a seamless development process, where the generality of the concepts and notations helps reduce the magnitude of the transitions between successive steps in the lifecycle.

结果是一个无缝的开发过程,概念和符号的原则帮助我们减少开发周期中持续步骤之间的转化量.

These requirements exclude two cases, still frequently encountered but equally unsatisfactory:

这些需求排除了二种情况,但这二种情况仍然频繁遇到且相当不令人满意:

• The use of object-oriented concepts for analysis and design only, with a method and notation that cannot be used to write executable software.

面向对象概念的用途只是用于分析和设计,方法和符号并不能用来编写可执行软件.

• The use of an object-oriented programming language which is not suitable for analysis and design.

面向对象程序语言的用途并不适用于分析和设计.

In summary:

An object-oriented language and environment, together with the supporting method, should apply to the entire lifecycle, in a way that minimizes the gaps between successive activities.

一个面向对象的语言和环境,和支持方法一起,应该适用于整个生命周期,并在持续的使用中将其中的间隙减至最小.

总之:

总之:

Classes

The object-oriented method is based on the notion of class. Informally, a class is a software element describing an abstract data type and its partial or total implementation.An abstract data type is a set of objects defined by the list of operations, or features, applicable to these objects, and the properties of these operations.

面向对象的方法建立在类的观念基础上.通常,一个类就是一个软件元素,其描述了一个抽象数据类型和它的局部或总体的实现.一个抽象数据类型就是一组对象,这组对象被一系列的操作,或应用于这些对象的特性和这些操作的属性所定义.

The method and the language should have the notion of class as their central concept.

方法和语言应该把类的观念作为其核心概念.

Assertions

断言

The features of an abstract data type have formally specified properties, which should be reflected in the corresponding classes. Assertions — routine preconditions, routine postconditions and class invariants — play this role. They describe the effect of features on objects, independently of how the features have been implemented.

抽象数据类型的特性有指定形式的属性,其应该被反映在对应的类中. 断言—例程预处理(routine preconditions),例程后处理(routine postconditions)和类不变量(class invariants)--扮演了这个角色.它们描述对象特性的效果和如何独立地实现特性.

Assertions have three major applications: they help produce reliable software; they provide systematic documentation; and they are a central tool for testing and debugging object-oriented software.

断言有三个主要的应用:它们帮助产生可靠的软件;它们提供系统的文档;并且它们对于测试和除错面向对象软件而言是一个核心工具.

The language should make it possible to equip a class and its features with assertions (preconditions, postconditions and invariants), relying on tools to produce documentation out of these assertions and, optionally, monitor them at run time.

语言应该尽可能的运用类和它的断言特性(预处理, 后处理和不变量),同时依赖于工具从这些断言中产生文档,而且在运行时候可任意的监控它们.

In the society of software modules, with classes serving as the cities and instructions (the actual executable code) serving as the executive branch of government, assertions provide the legislative branch. We shall see below who takes care of the judicial system.

在软件模块的组织中,类就如同城市,指令(实际执行的代码)如政府的执行机关,断言为立法机关.我们将在下面看到谁是司法系统.

Classes as modules

模块类

Object orientation is primarily an architectural technique: its major effect is on the modular structure of software systems.

面向对象主要是一种架构技术: 它主要的作用是在软件系统的模块结构上.

The key role here is again played by classes. A class describes not just a type of objects but also a modular unit. In a pure object-oriented approach:

这里,类再一次扮演了关键角色.一个类不但描述一个对象类型而且是一个模块单元(modular unit).在纯粹的面向对象的方式中:

Classes should be the only modules.

类应该是单一的模块.

In particular, there is no notion of main program, and subprograms do not exist as independent modular units. (They may only appear as part of classes.) There is also no need for the “packages” of languages such as Ada

, although we may find it convenient for management purposes to group classes into administrative units, called clusters.

特别地,这里没有主程序的观念,子程序也并不作为独立的模块单元存在.(它们可以只作为类的一部份而出现.) 这里也没有像Ada语言那样,对语言“包”的需要,然而我们发现为了管理的目的而以管理单元对类分组非常的方便,这钟方法称之为群集(clusters).

Classes as types

类型类

The notion of class is powerful enough to avoid the need for any other typing mechanism:

类的观念足够有效的避免对任何其它的类型机制的需要:

Every type should be based on a class.

任何类型都应基于一个类.

Even basic types such as INTEGER and REAL can be derived from classes; normally such classes will be built-in rather than defined anew by each developer.

即使是基本类型,如整数(INTEGER)和实数(REAL),都源自类;通常,这些类是内建的,不需要每个开发者重新定义.

Feature-based computation

基于特性的计算

In object-oriented computation, there is only one basic computational mechanism: given a certain object, which (because of the previous rule) is always an instance of some class, call a feature of that class on that object. For example, to display a certain window on a screen, you call the feature display on an object representing the window — an instance of class WINDOW. Features may also have arguments: to increase the salary of an employee e by n dollars, effective at date d, you call the feature raise on e, with n and d as arguments.

在面向对象的计算中,只有一个基本的计算机制:假设一个确定的对象,这个对象始终是一些类的一个实例(instance),称之为在对象上的类的一个特性.举例来说,要在荧屏上显示一个窗囗,您在一个用来描绘窗囗的对象上调用特性display--这个对象是类WINDOW的一个实例. 特性也可能有参数: 在有效日期d,要增加职员e的n美元薪水,您可以调用在e上的特性raise,并把n和d作为参数.

Just as we treat basic types as predefined classes, we may view basic operations (such as addition of numbers) as special, predefined cases of feature call, a very general mechanism for describing computations:

正如我们把基本的类型当作预先定义的类一样,我们可以把基本的运算(如数字的加法)看作是特殊的,预先定义的特性调用,是描述计算的一个非常通用的机制:

Feature call should be the primary computational mechanism.

特性调用应该成为主要的计算机制.

A class which contains a call to a feature of a class C is said to be a client of C. Feature call is also known as message passing; in this terminology, a call such as the above will be described as passing to e the message “raise your pay”, with arguments d and n.

一个类,其包含了对C类的一个特性的调用,称之为C的客户端(client).特性调用也称之为消息传递(message passing);在这个术语中,象上述这样的调用可以描述为:传递给e”加薪”的消息,同时传递参数d和n.

Information hiding

消息隐藏

When writing a class, you will sometimes have to include a feature which the class needs for internal purposes only: a feature that is part of the implementation of the class, but not of its interface. Others features of the class — possibly available to clients — may call the feature for their own needs; but it should not be possible for a client to call it directly.

当编写一个类的时候,您有时不的不包括一个只在类内部使用的特性:这个特性是类的实现的一部份,并不是它的接口(interface).其它的类特性--可能对客户端有效—可以在它们自己需要的时候调用这个特性;但是它不可以被一个客户端直接地调用.

The mechanism which makes certain features unfit for clients’ calls is called information hiding. As explained in a later chapter, it is essential to the smooth evolution of software systems.

不让客户端调用到特定的特性的机制叫做信息隐藏.如稍后所述,它对软件系统的平稳发展是很重要的.

In practice, it is not enough for the information hiding mechanism to support exported features (available to all clients) and secret features (available to no client); class designers must also have the ability to export a feature selectively to a set of designated clients.

在实践中,用信息隐藏机制来支持输出特性(所有的客户端都可调用)和秘密特性(客户端不可调用)并不足够;类的设计者也一定有能力对一组指定的客户端有选择地开放特性.

It should be possible for the author of a class to specify that a feature is available to all clients, to no client, or to specified clients.

应该让类的作者能够指定:一个特性对所有的客户端有效,对客户端无效,或对特定的客户端有效.

An immediate consequence of this rule is that communication between classes should be strictly limited. In particular, a good object-oriented language should not offer any notion of global variable; classes will exchange information exclusively through feature calls, and through the inheritance mechanism.

这条规则的直接后果是在类之间的通讯被严格地限制.尤其是一个好的面向对象语言不应该提供任何全局变量的观念;类会通过特性调用和继承机制不公开地交换信息.

Exception handling

异常隐藏

Abnormal events may occur during the execution of a software system. In object-oriented computation, they often correspond to calls that cannot be executed properly, as a result of a hardware malfunction, of an unexpected impossibility (such as numerical overflow in an addition), or of a bug in the software.

反常事件在软件系统的运行期间可能会发生.在面向对象的计算中,它们时常响应错误执行的调用,这可能是一个硬件的故障,一件料想不到之事(如加法中的数字溢出),或软件中的一个错误.

To produce reliable software, it is necessary to have the ability to recover from such situations. This is the purpose of an exception mechanism.

要产生可靠的软件,就要求必需有从上述情况中恢复过来的能力.这就是异常机制的目的.

The language should provide a mechanism to recover from unexpected abnormal situations.

语言应该提供一个从意外的反常情形中恢复的机制.

In the society of software systems, as you may have guessed, the exception mechanism is the third branch of government, the judicial system (and the supporting police force).

在软件系统的体系中,您可能已经猜到,异常机制是政府的第三个分枝,既司法系统(和支援警力).

Static typing

静态类型

When the execution of a software system causes the call of a certain feature on a certain object, how do we know that this object will be able to handle the call? (In message terminology: how do we know that the object can process the message?)

当软件系统执行的时候,调用了一个对象上的某个特性,我们如何知道这个对象能够处理调用?(用信息术语来说:我们如何知道对象能处理信息?)

To provide such a guarantee of correct execution, the language must be typed. This means that it enforces a few compatibility rules; in particular:

为了要提供正确执行的保证,语言一定要定义类型.这意谓着它加强了一些相容性的规则;特别是:

• Every entity (that is to say, every name used in the software text to refer to run-time objects) is explicitly declared as being of a certain type, derived from a class.

作为从一个类派生出的一个特定的类型,每个实体(也就是说是每个命名,即被用于软件引用的运行时的对象)要明确地被声明.

• Every feature call on a certain entity uses a feature from the corresponding class (and the feature is available, in the sense of information hiding, to the caller’s class).

访问一个特定的实体的每个特性,使用了对应的类的一个特性(而且,在信息隐藏的意思中,特性对于调用者的类来说是有效的).

• Assignment and argument passing are subject to conformance rules, based on inheritance, which require the source’s type to be compatible with the target’s type.

赋值和参数传递受制于一致性规则(conformance rules),这是基于继承需要源类型是与目的类型一致的原因.

In a language that imposes such a policy, it is possible to write a static type checker which will accept or reject software systems, guaranteeing that the systems it accepts will not cause any “feature not available on object” error at run time.

在一个强制实行上述政策的语言中,可以编写一个静态类型检验程序(static type checker),这个程序将接受或拒绝软件系统,确保它接受的系统在运行的时候不会引起任何的”对象上的特性无效”的错误.

A well-defined type system should, by enforcing a number of type declaration and compatibility rules, guarantee the run-time type safety of the systems it accepts.

一个定义明确的类型体系应该是,通过强制实行大量的类型声明和兼容性规则,确保它所接受的系统运行时类型安全.

Genericity

泛型

For typing to be practical, it must be possible to define type-parameterized classes, known as generic. A generic class LIST [G] will describe lists of elements of an arbitrary type represented by G, the “formal generic parameter”; you may then declare specific lists through such derivations as LIST [INTEGER] and LIST [WINDOW], using types INTEGER and WINDOW as “actual generic parameters”. All derivations share the same class text.

应该尽可能的定义参数化类型的类来实现实际的类型定义,即泛化.一个泛化类LIST[G]描述为一系列可被定义G的任何元素,既”形式上的泛化叁数”;然后您可以声明具体的形式如LIST [INTEGER]和LIST [WINDOW]这样类似的派生,使用INTEGER和WINDOW类型作为”实际的泛化叁数”.所有的派生共享相同的类代码.

It should be possible to write classes with formal generic parameters representing arbitrary types.

应该尽可能地编写具有形式上的泛化叁数的类来表现任意的类型.

This form of type parameterization is called unconstrained genericity. A companion facility mentioned below, constrained genericity, involves inheritance.

这种参数化类型的形式叫做非限定性泛型(unconstrained genericity).另一个相对的工具,包括继承的限定性泛型(constrained genericity),将在下面说明.

Single inheritance

单重继承

Software development involves a large number of classes; many are variants of others. To control the resulting potential complexity, we need a classification mechanism, known as inheritance. A class will be an heir of another if it incorporates the other’s features in addition to its own. (A descendant is a direct or indirect heir; the reverse notion is ancestor.)

It should be possible to define a class as inheriting from another.

应该尽可能继承其它类来定义一个新类.

软件开发包括了大量的类;许多是其它一些的变体.为了控制产生潜在复杂的结果,我们需要一个分类机制,即继承.如果一个类要合并除了它自己之外的另一个类的其它特性,那么这个类要成为它的继承人.(一个后裔是直接的或间接的继承人;相反的概念是祖先)。

Inheritance is one of the central concepts of the object-oriented methods and has profound consequences on the software development process.

继承是面向对象方法的核心概念之一,在软件发展的过程中有着重要地影响.

Multiple inheritance

多重继承

We will often encounter the need to combine several abstractions. For example a class might model the notion of “infant”, which we may view both as a “person”, with the associated features, and, more prosaically, as a “tax-deductible item”, which earns some deduction at tax time. Inheritance is justified in both cases. Multiple inheritance is the guarantee that a class may inherit not just from one other but from as many as is conceptually justified.

我们时常会遇到联合几个抽象概念的需求.举例来说,一个类可以模拟”婴儿”的思想,我们也可以从关联的特性把其看作一个”人”,同时,更实际的是,作为一个”减税的条款”,在交税时可以获得一些减免. 继承在这两种情况下中都证明无误.多重继承确保了一个类不但可以从一个父类而且可以从多个父类继承的概念正确性.

Multiple inheritance raises a few technical problems, in particular the resolution of name clashes (cases in which different features, inherited from different classes, have the same name). Any notation offering multiple inheritance must provide an adequate solution to these problems.

多重继承会引起一些技术上的问题,特别是名字冲突(从不同的类继承不同特性却有相同名字的情况).提供多重继承的任何符号(语言)一定要妥善解决这些问题.

It should be possible for a class to inherit from as many others as necessary, with an adequate mechanism for disambiguating name clashes.

一个类应该可以能够从所有需要的类中继承下来,并有一个适当的机制来消除名字的歧义.

The solution developed in this book is based on renaming the conflicting features in the heir class.

在本书中开发的解决方案,是以在继承类中重命名冲突的特性为基础的.

Repeated inheritance

重复继承

Multiple inheritance raises the possibility of repeated inheritance, the case in which a class inherits from another through two or more paths, as shown.

多重继承引发了重复继承的可能性,这种情况是一个类继承自另外一个类经过了二个或更多的路径,如下所示.

In such a case the language must provide precise rules defining what happens to features inherited repeatedly from the common ancestor, A in the figure. As the discussion of repeated inheritance will show, it may be desirable for a feature of A to yield just one feature of D in some cases (sharing), but in others it should yield two (replication). Developers must have the flexibility to prescribe either policy separately for each feature.

这种情况下,语言必须提供精确的规则来定义从共同的祖先(图中的A)重复继承下来的特性所发生的情况.如重复继承所讨论的,在一些情况下(共享)是合理的,即A的一个特性只是产生了D中的一个特性,但是在其它的情况下,它可能产生二个(复制).对每个特性开发者必须要灵活的指定各自的方针.

Precise rules should govern the fate of features under repeated inheritance, allowing developers to choose, separately for each repeatedly inherited feature, between sharing and replication.

精确的规则应该管理在重复继承下的特性的命运,允许开发者分别的为每个重复继承的特性在共享和复制之间作出选择.

Constrained genericity

限定性泛型

The combination of genericity and inheritance brings about an important technique, constrained genericity, through which you can specify a class with a generic parameter that represents not an arbitrary type as with the earlier (unconstrained) form of genericity, but a type that is a descendant of a given class.

泛型和继承的组合带来了一个重要的技术,限定性泛型,通过它您能指定一个带有泛化参数的类,这个参数并不是一个如先前的(非限定性)泛型形式那样的任意类型,而是一个继承自特定类的派生类.

A generic class SORTABLE_LIST, describing lists with a sort feature that will reorder them sequentially according to a certain order relation, needs a generic parameter representing the list elements’ type. That type is not arbitrary: it must support an order relation. To state that any actual generic parameter must be a descendant of the library class COMPARABLE, describing objects equipped with an order relation, use constrained genericity to declare the class as SORTABLE_LIST [G –> COMPARABLE].

一个泛化类SORTABLE_LIST, 描述了带有一个sort特性的列表,此特性依照一个特定的次序关系重新排列顺序,这需要一个泛化的参数来表示元素列表的类型.类型不是任意的:它需要支持一定的次序关系.规定了任何实际的泛化参数(实参)一定是继承自类库COMPARABLE,并描述对象之间的次序关系,要象SORTABLE_LIST [G –> COMPARABLE]这样使用限定性泛型来声明类.

The genericity mechanism should support the constrained form of genericity.

泛型机制应该支持泛型的限定性形态.

Redefinition

重定义

When a class is an heir of another, it may need to change the implementation or other properties of some of the inherited features. A class SESSION describing user sessions in an operating system may have a feature terminate to take care of cleanup operations at the end of a session; an heir might be REMOTE_SESSION, handling sessions started from a different computer on a network. If the termination of a remote session requires supplementary actions (such as notifying the remote computer), class REMOTE_SESSION will redefine feature terminate.

当一个类继承自另外一个类的时候,它可能需要改变实现或其它一些继承特性中的属性.类SESSION描述了在一个操作系统中的用户会话(User Session),它有一个特性terminate,在会话结束的时候监控清除操作;一个派生类REMOTE_SESSION处理着在网络上的另一个计算机上启动的会话.如果远程会话的终止需要触发额外的行动(如通知远程计算机),类REMOTE_SESSION将会重新定义特性terminate.

Redefinition may affect the implementation of a feature, its signature (type of arguments and result), and its specification.

重定义可能影响特性的实现,特性的标记(参数和结果的类型),和特性的规格.

It should be possible to redefine the specification, signature and implementation of an inherited feature.

可以重定义继承特性的规格,标记和实现.

Polymorphism

多态

With inheritance brought into the picture, the static typing requirement listed earlier would be too restrictive if it were taken to mean that every entity declared of type C may only refer to objects whose type is exactly C. This would mean for example that an entity of type C (in a navigation control system) could not be used to refer to an object of type MERCHANT_SHIP or SPORTS_BOAT, both assumed to be classes inheriting from BOAT.

随着继承的介绍,如果早期所列的静态类型只是意味着每一个C类型所声明的实体仅仅严格匹配那些C类型的对象,那么这会有很大的局限性.举例来说,这意味着类型C的实体(在一个航行控制系统中)不可以用来指代类型MERCHANT_SHIP或SPORTS_BOAT的一个对象,假定两者都是从BOAT继承下来.

As noted earlier, an “entity” is a name to which various values may become attached at run time. This is a generalization of the traditional notion of variable.

如先前所描述,一个”实体”是指在运行的时候,各种不同的值所赋的名字.这是变量的传统观念的一个概括.

Polymorphism is the ability for an entity to become attached to objects of various possible types. In a statically typed environment, polymorphism will not be arbitrary, but controlled by inheritance; for example, we should not allow our BOAT entity to become attached to an object representing an object of type BUOY, a class which does not inherit from BOAT.

多态是指一个实体能传递给各种不同类型的对象的能力.在一个静态的类型环境中,多态不是独立的,而是被继承所控制;举例来说,我们可以不允许我们的BOAT实体传递给一个BUOY对象,这个对象并不是从BOAT继承.

It should be possible to attach entities (names in the software texts representing run-time objects) to run-time objects of various possible types, under the control of the inheritance-based type system.

在基于继承类型的系统控制之下,可以把实体(软件代码中描述运行对象的名字)赋给各种可能类型的运行时对象.

Dynamic binding

动态绑定

The combination of the last two mechanisms mentioned, redefinition and polymorphism, immediately suggests the next one. Assume a call whose target is a polymorphic entity, for example a call to the feature turn on an entity declared of type BOAT. The various descendants of BOAT may have redefined the feature in various ways. Clearly, there must be an automatic mechanism to guarantee that the version of turn will always be the one deduced from the actual object’s type, regardless of how the entity has been declared. This property is called dynamic binding.

重定义和多态,这最后二个机制的组合,立刻引发了下一个议题.假设一个目标是多态实体的调用,例如在一个声明为类型BOAT的实体上特性turn的调用. BOAT的各种不同的派生类可以用各种不同的方式重新定义特性.明显地,这里一定要有一个自动机制来保证turn版本总是一个从实际对象的类型中推导出的,而不管实体如何声明.这个特性叫做动态绑定.

Calling a feature on an entity should always trigger the feature corresponding to the type of the attached run-time object, which is not necessarily the same in different executions of the call.

调用实体上的一个特性应该总是触发相应的运行时对象的类型上的特性,在不同的调用执行中,这个运行时对象不必相同.

Dynamic binding has a major influence on the structure of object-oriented applications, as it enables developers to write simple calls (meaning, for example, “call feature turn on entity my_boat”) to denote what is actually several possible calls depending on the corresponding run-time situations. This avoids the need for many of the repeated tests (“Is this a merchant ship? Is this a sports boat?”) which plague software written with more conventional approaches.

在面向对象的应用程序的结构中, 动态绑定有一个主要的结果,它能够让开发者编写出简单的调用(举例来说,”调用实体my_boat上的turn特性”)来表示实际上几种可能的调用,这些调用依赖相应的运行时状态.这避免了许多重复测试的需要 (“这是这一艘商船?这是一艘运动船吗?”)这正是令那些使用传统方法编写的软件所头痛的事.

Run-time type interrogation

运行时类型问题

Object-oriented software developers soon develop a healthy hatred for any style of computation based on explicit choices between various types for an object. Polymorphism and dynamic binding provide a much preferable alternative. In some cases, however, an object comes from the outside, so that the software author has no way to predict its type with certainty. This occurs in particular if the object is retrieved from external storage, received from a network transmission or passed by some other system.

在一个对象的各种不同的类型之间做出明确选择,面向对象的软件开发者很快对于这种计算类型表示出了相当大的憎恨.多态和动态绑定提供了一个更可取的替代选择.然而在一些情况里,一个对象来自外部,所以软件作者没有办法预知它的确定类型.特别的,如果对象是从外部存储中取回,从网络传输收到或经过一些其它的系统,这种现象就会发生.

The software then needs a mechanism to access the object in a safe way, without violating the constraints of static typing. Such a mechanism should be designed with care, so as not to cancel the benefits of polymorphism and dynamic binding.

那么,软件需要一个用安全的方法存取对象的机制,而不违犯静态类型的限制.这样的机制需要小心仔细地设计,免得抵消了多态和动态绑定所带来的好处.

The assignment attempt operation described in this book satisfies these requirements. An assignment attempt is a conditional operation: it tries to attach an object to an entity; if in a given execution the object’s type conforms to the type declared for the entity, the effect is that of a normal assignment; otherwise the entity gets a special “void” value. So you can handle objects whose type you do not know for sure, without violating the safety of the type system.

在本书中描述的赋值尝试(assignment attempt)运算能满足这些需求.一个赋值尝试就是一个条件运算:它试图把一个对象赋给一个实体;如果在一个特定的执行中对象的类型与实体所声明的类型一致,那么结果是正常的赋值;否则实体得到一个特别的”void”值.因此您就能处理那些您不能确定类型的对象,而不违犯类型体系的安全性.

It should be possible to determine at run time whether the type of an object conforms to a statically given type.

应该可以决定在运行的时侯一个对象的类型是否符合一个静态的特定类型.

Deferred features and classes

延期的功能和类

In some cases for which dynamic binding provides an elegant solution, obviating the need for explicit tests, there is no initial version of a feature to be redefined. For example class BOAT may be too general to provide a default implementation of turn. Yet we want to be able to call feature turn to an entity declared of type BOAT if we have ensured that at run time it will actually be attached to objects of such fully defined types as MERCHANT_SHIP and SPORTS_BOAT.

在一些情况中,动态绑定提供了极好的解决方案,消除了显而易见的测试需求,这里,并没有一个特性的初始版本被重新定义.举例来说, BOAT类可能是太通用而无法提供一个缺省的turn的实现.如果我们能确定在运行的时候它实际上被赋到MERCHANT_SHIP和SPORTS_BOAT这种完整的定义类型的对象上, 我们仍然希望能够调用一个声明为BOAT类型的实体上的turn特性.

In such cases BOAT may be declared as a deferred class (one which is not fully implemented), and with a deferred feature turn. Deferred features and classes may still possess assertions describing their abstract properties, but their implementation is postponed to descendant classes. A non-deferred class is said to be effective.

在这种的情况下,BOAT可以声明成一个延期类(一个没有完全实现的类),并定义了一个延期特性turn. 延期特性和延期类可以一直保持着描述它们的抽象属性的断言,但其实现被延期到派生类.一个非延期类说成是有效类(effective).

It should be possible to write a class or a feature as deferred, that is to say specified but not fully implemented.

应当尽可能地编写一个延期类或一个延期特性,也就是说只指定却不完整实现.

Deferred classes (also called abstract classes) are particularly important for objectoriented analysis and high-level design, as they make it possible to capture the essential aspects of a system while leaving details to a later stage.

延期类(也说成抽象类)对于面向对象的分析和高水准的设计特别重要,因为它使只捕获系统的本质方面而把细节留给后面阶段成为可能.

Memory management and garbage collection

内存管理和垃圾收集

The last point on our list of method and language criteria may at first appear to belong more properly to the next category — implementation and environment. In fact it belongs to both. But the crucial requirements apply to the language; the rest is a matter of good engineering.

在我们的方法和语言标准的列表上,这是最后一条,看起来这条可能属于下一个种类—实现和环境更适当一些.事实上它属于两者.但是决定性的需求牵涉到语言方面;其余者是良好的工程性的问题.

Object-oriented systems, even more than traditional programs (except in the Lisp world), tend to create many objects with sometimes complex interdependencies. A policy leaving developers in charge of managing the associated memory, especially when it comes to reclaiming the space occupied by objects that are no longer needed, would harm both the efficiency of the development process, as it would complicate the software and occupy a considerable part of the developers’ time, and the safety of the resulting systems, as it raises the risk of improper recycling of memory areas. In a good object-oriented environment memory management will be automatic, under the control of the garbage collector, a component of the runtime system.

面向对象系统,甚至更多的传统程序(除了LISP领域),趋向产生许多复杂的互相依赖的对象.让开发者负责相关的内存管理,特别当涉及回收不再需要的对象所占领的空间的时候,这个方式会伤害开发过程的效率,同时,它会使软件更复杂,占用开发者相当的时间和引发最终系统安全性问题,它也提升了内存区域中不恰当回收的危险性.在一个好的面向对象环境里,在运行时系统组件:垃圾收集器(garbage collector)的控制之下,内存管理应是自动的.

The reason this is a language issue as much as an implementation requirement is that a language that has not been explicitly designed for automatic memory management will often render it impossible. This is the case with languages where a pointer to an object of a certain type may disguise itself (through conversions known as “casts”) as a pointer of another type or even as an integer, making it impossible to write a safe garbage collector.

如同一个实现需求,这是一个语言的议题,原因是一个没有明确地设计自动内存管理的语言将是不可能实现上述要求的.一个特定类型的对象的一个指针可能伪装成另外一个类型的指针,甚至一个整数,这种情况下,在这种语言中编写一个安全的垃圾收集器根本不可能.

The language should make safe automatic memory management possible, and the implementation should provide an automatic memory manager taking care of garbage collection.

语言应该使安全的自动内存管理成为可能,并且其实现应该提供一个自动的内存管理器来掌管垃圾收集.

2.3 IMPLEMENTATION AND ENVIRONMENT

2.3 实现和环境

We come now to the essential features of a development environment supporting objectoriented software construction.

现在,我们来介绍一个支持面向对象软件构造的开发环境的基本特性.

Automatic update

自动更新

Software development is an incremental process. Developers do not commonly write thousands of lines at a time; they proceed by addition and modification, starting most of the time from a system that is already of substantial size.

软件开发是一个渐进的过程.开发者并不是一次编写数千行代码;它们通过增加和修改来持续进行,大部份时间是从一个已有的系统开始的.

When performing such an update, it is essential to have the guarantee that the resulting system will be consistent. For example, if you change a feature f of class C, you must be certain that every descendant of C which does not redefine f will be updated to have the new version of f, and that every call to f in a client of C or of a descendant of C will trigger the new version.

当完成这样的一个更新时,很重要的一点是保证最终系统一致.举例来说,如果您改变C类的f特性,您必须要确保没有重定义f的C的每个派生类将被更新f的新版本,同时C的客户端或派生类对f的每个调用都将触发新的版本.

Conventional approaches to this problem are manual, forcing the developers to record all dependencies, and track their changes, using special mechanisms known as “make files” and “include files”. This is unacceptable in modern software development, especially in the object-oriented world where the dependencies between classes, resulting from the client and inheritance relations, are often complex but may be deduced from a systematic examination of the software text.

这个问题的传统方法是手工操作,强迫开发者记录所有的关联,并追踪它们的变化,并使用特别的机制如我们所知的"make files"和"include files".这在现代的软件发展中是无法接受的,尤其是在面向对象的世界里,类之间的关联,客户端和继承关系之间的相关点时常是复杂的,但是可以从软件代码文本的系统检查中推论出.

System updating after a change should be automatic, the analysis of interclass dependencies being performed by tools, not manually by developers.

在一个更改之后,系统更新应该是自动的,类之间的关联分析应被工具完成,而不是开发者手工操作.

It is possible to meet this requirement in a compiled environment (where the compiler will work together with a tool for dependency analysis), in an interpreted environment, or in one combining both of these language implementation techniques.

尽可能在编译环境中(在这里编译器将会连同关联分析工具一起工作),在解释环境中,或在一个联合这些语言实现技术的环境中实现这个需求.

Fast update

快速更新

In practice, the mechanism for updating the system after some changes should not only be automatic, it should also be fast. More precisely, it should be proportional to the size of the changed parts, not to the size of the system as a whole. Without this property, the method and environment may be applicable to small systems, but not to large ones.

在实践中,在产生变化后更新系统的机制不但应该是自动的,而且更应该是快速的.更精确的说,它应该与变化部份大小成比例,而不是针对整个系统的大小.没有这个属性的话,方法和环境也许可以应用在小系统上,但是不能适用于大系统.

The time to process a set of changes to a system, enabling execution of the updated version, should be a function of the size of the changed components, independent of the size of the system as a whole.

对一个系统进行一组改变,并确保更新过的版本能够执行,这个时间应该是与被改变组件的大小密切相关,并不依赖于整体系统的大小.

Here too both interpreted and compiled environments may meet the criterion, although in the latter case the compiler must be incremental. Along with an incremental compiler, the environment may of course include a global optimizing compiler working on an entire system, as long as that compiler only needs to be used for delivering a final product; development will rely on the incremental compiler.

这里,尽管在后一个情况中,编译器一定是增量的,但解释和编译环境也可能符合标准.连同一个增量编译器(incremental compiler)一起,环境当然包括一个工作于整个系统的全面最佳化编译器,只要那个编译器仅仅需要用于发布最终的产品;开发将会依靠于增量编译器.

Persistence

持久性

Many applications, perhaps most, will need to conserve objects from one session to the next. The environment should provide a mechanism to do this in a simple way.

许多应用程序,也许是极大多数的,将会从一个会话到下一个会话之间保存对象.环境应该提供一个机制以简单的方式做这件事.

An object will often contain references to other objects; since the same may be true of these objects, this means that every object may have a large number of dependent objects, with a possibly complex dependency graph (which may involve cycles). It would usually make no sense to store or retrieve the object without all its direct and indirect dependents. A persistence mechanism which can automatically store an object’s dependents along with the object is said to support persistence closure.

一个对象总是会包含其它对象的引用;由于这些对象可能都一样,这意味着每个对象可能有很多的关联对象,伴随着一个也许很复杂的关联关系图(可能含有循环关系).通常没什么意义来储存或取回没有直接和间接关联的对象.一个能自动地储存对象及其关联的持久性机制被称作持久性闭包(persistence closure).

A persistent storage mechanism supporting persistence closure should be available to store an object and all its dependents into external devices, and to retrieve them in the same or another session.

一个支持持久性闭包的持久性储存机制应该有效地储存一个对象及其关联到外部的装置,并从相同的或另外的会话中取回它们.

For some applications, mere persistence support is not sufficient; such applications will need full database support. The notion of object-oriented database is covered in a later chapter, which also explores other persistent issues such as schema evolution, the ability to retrieve objects safely even if the corresponding classes have changed.

对于一些应用程序,仅仅持久性支持并不充份;这样的应用程序需要完整的数据库支持(database support). 面向对象的数据库的观念在后面的章节中再讨论,在那时也会探究其它的持久性议题,如模式演变(schema evolution),安全取回对象的能力即使相关的类已经改变.

Documentation

文档

Developers of classes and systems must provide management, customers and other developers with clear, high-level descriptions of the software they produce. They need tools to assist them in this effort; as much as possible of the documentation should be produced automatically from the software texts. Assertions, as already noted, help make such software-extracted documents precise and informative.

类和系统的开发者必须提供清晰,高水准的软件描述给管理层,客户和其它的开发者.他们需要工具协助以完成这个成果;许多的文档应该尽可能的从软件代码中自动地产生.正如先前所说,断言会帮助得到这种精确和信息化的萃取于软件的文件.

Automatic tools should be available to produce documentation about classes and systems.

自动工具应该有效地产生有关类和系统的文档.

Browsing

浏览

When looking at a class, you will often need to obtain information about other classes; in particular, the features used in a class may have been introduced not in the class itself but in its various ancestors. This puts on the environment the burden of providing developers with tools to examine a class text, find its dependencies on other classes, and switch rapidly from one class text to another.

当查看一个类的时候,您时常需要获得关于其它类的信息;尤其是在一个类中使用的特性可能没有在类本身中介绍,而在它的各种不同的父类中出现.这增加了开发环境的义务,即需要提供工具给开发者类查看一个类文本,找出其它类上的关联,并且在类文本之间能够快速转换.

This task is called browsing. Typical facilities offered by good browsing tools include: find the clients, suppliers, descendants, ancestors of a class; find all the redefinitions of a feature; find the original declaration of a redefined feature.

Interactive browsing facilities should enable software developers to follow up quickly and conveniently the dependencies between classes and features.

交互式浏览工具应该使软件开发者能够快速而方便地追踪在类和特性之间的关联.

这项任务叫做浏览.优秀的浏览工具所提供的典型功能包括:查找某个类的客户端,供应者,继承者,和父类;找出所有特性之重定义;找被重定义特性的最初声明.

2.4 LIBRARIES

2.4 库

One of the characteristic aspects of developing software the object-oriented way is the ability to rely on libraries. An object-oriented environment should provide good libraries, and mechanisms to write more.

对于发展中的软件之面向对象方法,一个的典型方面是依靠库的能力.一个面向对象的环境应该能提供优秀的库和机制来进行更多的扩展.

Basic libraries

基本库

The fundamental data structures of computing science — sets, lists, trees, stacks¼ — and the associated algorithms — sorting, searching, traversing, pattern matching — are ubiquitous in software development. In conventional approaches, each developer implements and re-implements them independently all the time; this is not only wasteful of efforts but detrimental to software quality, as it is unlikely that an individual developer who implements a data structure not as a goal in itself but merely as a component of some application will attain the optimum in reliability and efficiency.

计算科学中数据结构的基础—组,列表,树,栈…—和相关的运算法则—排序,查找,遍历,模式匹配—是普遍存在于软件开发之中.在传统的方式中,每个开发者始终独立地实现和重新实现它们;这不但白费努力而且不利于软件品质,同时,如果一个独立开发者实现一个数据结构并不是自己的一个目标而仅仅是一些应用程序的一个组件,对他而言不太可能会获得最佳的可靠性和效率.

An object-oriented development environment must provide reusable classes addressing these common needs of software systems.

Reusable classes should be available to cover the most frequently needed data structures and algorithms.

复用类应该能够有效地覆盖最常见的数据结构和算法之需求.

一个面向对象的开发环境必须提供复用类来处理这些软件系统的共同需求.

Graphics and user interfaces

图形和用户界面

Many modern software systems are interactive, interacting with their users through graphics and other pleasant interface techniques. This is one of the areas where the objectoriented model has proved most impressive and helpful. Developers should be able to rely on graphical libraries to build interactive applications quickly and effectively.

许多现代的软件系统都是交互式的,它们的用户通过图形和其它友好的界面技术进行互动.这是面向对象模型所提供的最令人深刻印象和最有帮助的领域之一.开发者应该能够借助图形库快速和高效地建立交互式应用程序.

Reusable classes should be available for developing applications which provide their users with pleasant graphical user interface.

复用类应该对开发中的应用程序有效,这些应用程序提供友好的图形用户界面给其用户.

Library evolution mechanisms

库的演化机制

Developing high-quality libraries is a long and arduous task. It is impossible to guarantee that the design of library will be perfect the first time around. An important problem, then, is to enable library developers to update and modify their designs without wreaking havoc in existing systems that depend on the library. This important criterion belongs to the library category, but also to the method and language category.

开发高品质的库是一个长期和辛勤的任务.它不可能保证库的设计第一次运行就是完美的.那么,一个重要的问题是要使库的开发者能够更新和修改它们的设计而不让已使用库的现存系统得到破坏.这个重要的标准属于库的范畴,但也是方法和语言的范畴.

Mechanisms should be available to facilitate library evolution with minimal disruption of client software.

机制应该有效的促进库的演化而对客户端软件的影响最小.

Library indexing mechanisms

库索引机制

Another problem raised by libraries is the need for mechanisms to identify the classes addressing a certain need. This criterion affects all three categories: libraries, language (as there must be a way to enter indexing information within the text of each class) and tools (to process queries for classes satisfying certain conditions).

库引起的另一个问题是需要一种机制来区分处理某一特定需求的类.这个标准影响所有的三个种类:库,语言(那里一定有一个方法能在每个类的文本里加入索引信息)和工具(对满足某个特定条件的类进行查询).

Library classes should be equipped with indexing information allowing property-based retrieval.

类库应该装备有索引信息以便进行基于属性的查找.

2.5 FOR MORE SNEAK PREVIEW

2.5 更多的事先预览

Although to understand the concepts in depth it is preferable to read this book sequentially, readers who would like to complement the preceding theoretical overview with an advance glimpse of the method at work on a practical example can at this point read chapter 20, a case study of a practical design problem, on which it compares an O-O solution with one employing more traditional techniques.

虽然更好地读这本书需要更深入的理解概念,但想要在一个实际的例子上了解一下运行的方式来进一步验证上述理论观点的读者,此时可以先看第20章,那章有一个案例是研究一个实际的设计问题,它把OO解决方案与一个更传统的技术作了比较.

That case study is mostly self-contained, so that you will understand the essentials without having read the intermediate chapters. (But if you do go ahead for this quick peek, you must promise to come back to the rest of the sequential presentation, starting with chapter 3, as soon as you are done.)

那件案例的研究绝大部分都是独立的,所以您不需要阅读中间的章节就可以理解 (但是如果您跳去快速浏览了,一旦看完后,还是要回来继续从第3章开始.)

2.6 BIBLIOGRAPHICAL NOTES AND OBJECT RESOURCES

2.6 资源

This introduction to the criteria of object orientation is a good opportunity to list a selection of books that offer quality introductions to object technology in general.

[Waldén 1995] discusses the most important issues of object technology, focusing

on analysis and design, on which it is probably the best reference.

[Page-Jones 1995] provides an excellent overview of the method.

[Cox 1990] (whose first edition was published in 1986) is based on a somewhat different view of object technology and was instrumental in bringing O-O concepts to a much larger audience than before.

[Henderson-Sellers 1991] (a second edition is announced) provides a short overview of O-O ideas. Meant for people who are asked by their company to “go out and find out what that object stuff is about”, it includes ready-to-be-photocopied transparency masters, precious on such occasions. Another overview is [Eliëns 1995].

The Dictionary of Object Technology [Firesmith 1995] provides a comprehensive reference on many aspects of the method.

All these books are to various degrees intended for technically-minded people. There is also a need to educate managers. [M 1995] grew out of a chapter originally planned for the present book, which became a full-fledged discussion of object technology for executives. It starts with a short technical presentation couched in business terms and continues with an analysis of management issues (lifecycle, project management, reuse policies). Another management-oriented book, [Goldberg 1995], provides a complementary perspective on many important topics. [Baudoin 1996] stresses lifecycle issues and the importance of standards.

Coming back to technical presentations, three influential books on object-oriented languages, written by the designers of these languages, contain general methodological discussions that make them of interest to readers who do not use the languages or might even be critical of them. (The history of programming languages and books about them shows that designers are not always the best to write about their own creations, but in these cases they were.) The books are:

• Simula BEGIN [Birtwistle 1973]. (Here two other authors joined the language designers Nygaard and Dahl.)

• Smalltalk-80: The Language and its Implementation [Goldberg 1983].

• The C++ Programming Language, second edition [Stroustrup 1991].

More recently, some introductory programming textbooks have started to use objectoriented ideas right from the start, as there is no reason to let “ontogeny repeat phylogeny”, that is to say, take the poor students through the history of the hesitations and mistakes through which their predecessors arrived at the right ideas. The first such text (to my knowledge) was [Rist 1995]. Another good book covering similar needs is [Wiener 1996].

At the next level — textbooks for a second course on programming, discussing data structures and algorithms based on the notation of this book — you will find [Gore 1996] and [Wiener 1997]; [Jézéquel 1996] presents the principles of object-oriented software engineering.

The Usenet newsgroup comp.object, archived on several sites around the Web, is the natural medium of discussion for many issues of object technology. As with all such forums, be prepared for a mixture of the good, the bad and the ugly. The Object Technology department of Computer (IEEE), which I have edited since it started in 1995, has frequent invited columns by leading experts.

Magazines devoted to Object Technology include:

• The Journal of Object-Oriented Programming (the first journal in the field, emphasizing technical discussions but for a large audience), Object Magazine (of a more general scope, with some articles for managers), Objekt Spektrum (German), Object Currents (on-line), all described at http://www.sigs.com.

• Theory and Practice of Object Systems, an archival journal.

• L’OBJET (French), described at http://www.tools.com/lobjet.

The major international O-O conferences are OOPSLA (yearly, USA or Canada, see http://www.acm.org); Object Expo (variable frequency and locations, described at http://www.sigs.com); and TOOLS (Technology of Object-Oriented Languages and Systems), organized by ISE with three sessions a year (USA, Europe, Pacific), whose home page at http://www.tools.com also serves as a general resource on object technology and the topics of this book.

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有