面向對象軟件構造(第2版)-第7章 靜態結構: 類 (中)

 

7.4 A UNIFORM TYPE SYSTEM

7.4 一個統一的類型系統

 

An important aspect of the O-O approach as we will develop it is the simplicity and uniformity of the type system, deriving from a fundamental property:

OO方法的一個重要方面是類型系統的簡單化和統一性,這個我們即將研究的方面是得自於一個基本的屬性:

 

Object rule

Every object is an instance of some class.

對象規則

任何對象都是某個類的實例。

 

The Object rule will apply not just to composite, developer-defined objects (such as data structures with several fields) but also to basic objects such as integers, real numbers, boolean values and characters, which will all be considered to be instances of predefined library classes (INTEGER, REAL, DOUBLE, BOOLEAN, CHARACTER).

對象規則不但適用於複合的,開發者自定義的對象例如具有多個字段的數據結構,而且也適用於基本的對象,例如整數,實數,布爾值和字符,所有這些都被認爲是預定義的庫類(INTEGER, REAL, DOUBLE, BOOLEAN, CHARACTER)的實例

 

This zeal to make every possible value, however simple, an instance of some class may at first appear exaggerated or even extravagant. After all, mathematicians and engineers have used integers and reals successfully for a long time, without knowing they were manipulating class instances. But insisting on uniformity pays off for several reasons:

每個可能而簡單的值變成類的實例,這種熱忱起初看上去可能有些過於誇張甚至過分。 畢竟,數學家和工程師長期成功地使用着整數和實數,並不知道他們正操作着類的實例。但是,基於下列的幾個原因堅持統一性會帶來回報

 

• It is always desirable to have a simple and uniform framework rather than many special cases. Here the type system will be entirely based on the notion of class.

有一個簡單和一致的框架而不是許多特殊的情況總是值得的。這裏的類型系統將完全地基於類的概念。

 

• Describing basic types as ADTs and hence as classes is simple and natural. It is not hard, for example, to see how to define the class INTEGER with features covering arithmetic operations such as "+", comparison operations such as "<=", and the associated properties, derived from the corresponding mathematical axioms.

基本類型描述ADTs並進而爲類,這是簡單而自然的。例如,對於類INTEGER,其中的特性包括了從對應的數學定理中得來的術運算例如"+"較運算例如 <=和關聯的屬性,瞭解如何定義這個類並不困難。

 

• By defining the basic types as classes, we allow them to take part in all the O-O games, especially inheritance and genericity. If we did not treat the basic types as classes, we would have to introduce severe limitations and many special cases.

過把基本類型定義爲類,我們允許它們參加所有的OO活動,特別是繼承和泛型。如果不這樣的話,我們將不得不引進嚴格的限制和許多特例。

 

As an example of inheritance, classes INTEGER, REAL and DOUBLE will be heirs to more general classes: NUMERIC, introducing the basic arithmetic operations such as "+", "" and "S", and COMPARABLE, introducing comparison operations such as "<". As an example of genericity, we can define a generic class MATRIX whose generic parameter represents the type of matrix elements, so that instances of MATRIX [INTEGER] represent matrices of integers, instances of MATRIX [REAL] represent matrices of reals and so on. As an example of combining genericity with inheritance, the preceding definitions also allow us to use the type MATRIX [NUMERIC], whose instances represent matrices containing objects of type INTEGER as well as objects of type REAL and objects of any new type T defined by a software developer so as to inherit from NUMERIC.

作爲一個繼承的例子,類INTEGERREALDOUBLE將繼承自更通用的類:NUMERICCOMPARABLE,從NUMERIC得到基本的運算,如"+""""S",從COMPARABLE得到比較運算如"<"。作爲一個泛型的例子,我們能夠定義一個泛化類MATRIX,其泛化參數表示了矩陣元素的類型,因此,MATRIX [INTEGER]的實例表示了整數矩陣,MATRIX [REAL]的實例表示了實數矩陣,諸如此類。作爲一個聯合繼承的泛型例子,上述的定義也允許我們使用類型MATRIX [NUMERIC],其實例表示了矩陣可以容納類型INTEGER的對象,也可以容納類型REAL的對象,並且可以容納任何新類型T的對象,這個新類型是由軟件開發者定義,並從NUMERIC繼承而來。

 

With a good implementation, we do not need to fear any negative consequence from the decision to define all types from classes. Nothing prevents a compiler from having special knowledge about the basic classes; the code it generates for operations on values of types such as INTEGER and BOOLEAN can then be just as efficient as if these were built-in types in the language.

因爲有着良好的實現,從做出決定到把所有的類型義成類,我們不需要擔心任何消極的後果。編譯器總是具有關於基本類的特別知識那麼,爲諸如INTEGERBOOLEAN類型的值運算所生成的代碼能夠和內建在語言中的類型一樣的高效。

 

Reaching the goal of a fully consistent and uniform type system requires the combination of several important O-O techniques, to be seen only later: expanded classes, to ensure proper representation of simple values; infix and prefix operators, to enable usual arithmetic syntax (such as a < b or –a rather than the more cumbersome a.less_than (b) or a.negated); constrained genericity, needed to define classes which may be adapted to various types with specific operations, for example a class MATRIX that can represent matrices of integers as well as matrices of elements of other numeric types.

達到一個完全穩定和一致的類型系統的目的,這需要結合幾個重要的O-O術,稍後可以瞭解到的擴展類(expanded classes),來保證簡單值的正確的表示;綴和前綴運算符,來提供通常的算術語法(例如a < b–a而不是更加臃腫的a.less_than (b)a.negated);限制泛型,需要定義一個類,其可以適應具有特定運算的各種類型,例如類MATRIX,能夠代表整數矩陣,也可以代表其它數字類型元素的矩陣。

 

7.5 A SIMPLE CLASS

7.5 一個簡單的類

 

Let us now see what classes look like by studying a simple but typical example, which shows some of the fundamental properties applicable to almost all classes.

現在讓我們通過研究一個簡單卻很典型的例子來看類是什麼,這個例子顯示了一些幾乎對所有類都適用的基本屬性。

 

The features

特性

 

The example is the notion of point, as it could appear in a two-dimensional graphics system.

例子是一個點的概念,它出現在一個兩維的圖象系統中。

 

 

To characterize type POINT as an abstract data type, we would need the four query functions x, y, r, q. (The names of the last two will be spelled out as rho and theta in software texts.) Function x gives the abscissa of a point (horizontal coordinate), y its ordinate (vertical coordinate), r its distance to the origin, q the angle to the horizontal axis.

要把類型POINT描述成一個抽象數據類型,我們需要四個查詢函數xyrq。(在軟件代碼中最後兩個的名字讀成rhotheta。)函數x 給出了一個點的橫座標(水平座標),y是縱座標(垂直座標),r是到原點的距離,q是到水平軸的角度。

 

The values of x and y for a point are called its cartesian coordinates, those of r and q its polar coordinates. Another useful query function is distance, which will yield the distance between two points.

一個點的xy值叫做笛卡兒座標,rq叫做極座標。其它有用的查詢函數是distance,這是在兩點之間所產生的距離。

 

Then the ADT specification would list commands such as translate (to move a point by a given horizontal and vertical displacement), rotate (to rotate the point by a certain angle, around the origin) and scale (to bring the point closer to or further from the origin by a certain factor).

接着,ADT規格列出了命令,如translate(根據一個給定的水平和垂直位置移動一個點),rotate(根據一定的角度圍繞原點旋轉點)和scale(根據某個因素把點移近原點或移出原點)。

 

It is not difficult to write the full ADT specification including these functions and some of the associated axioms. For example, two of the function signatures will be

x: POINT ® REAL

translate: POINT ´ REAL ´ REAL ® POINT

and one of the axioms will be (for any point p and any reals a, b):

x (translate (p1, a, b)) = x (p1) + a

expressing that translating a point by <a, b> increases its abscissa by a.

要編寫包括這些函數和一些相關定理的完整的ADT規格,這並不困難。例如,其中兩個函數的標記式爲

x: POINT ® REAL

translate: POINT ´ REAL ´ REAL ® POINT

一個定理爲(對於任意的點p和任意實數a, b):

x (translate (p1, a, b)) = x (p1) + a

其表達了一個點移動<a, b>橫座標增量爲a

 

You may wish to complete this ADT specification by yourself. The rest of this discussion will assume that you have understood the ADT, whether or not you have written it formally in full, so that we can focus on its implementation — the class.

您也許希望單獨完成這個ADT規格。無論您曾經是否正式地完整編寫過ADT這次討論的餘下部分都將假設您已經瞭解了,因此我們可以集中在它的實現上——類。

 

Attributes and routines

屬性和例程

 

Any abstract data type such as POINT is characterized by a set of functions, describing the operations applicable to instances of the ADT. In classes (ADT implementations), functions will yield features — the operations applicable to instances of the class.

任何類似於POINT的抽象數據類型都被一組函數所描繪,函數描述了應用到ADT實例上的運算。在類(ADT實現)中,函數將產生特性——應用到類實例上的運算。

 

We have seen that ADT functions are of three kinds: queries, commands and creators. For features, we need a complementary classification, based on how each feature is implemented: by space or by time.

們已經知道了ADT函數有類:查詢,命令和創建符。對於特性,我們需要一個補充的分類,這基於每個特性的實現方式:根據間或是根據時間。

 

The example of point coordinates shows the difference clearly. Two common representations are available for points: cartesian and polar. If we choose Cartesian representation, each instance of the class will contain two fields representing the x and y of the corresponding point:

點座標的例子清楚地顯示出了這兩者的差別。點可以使用二種普通的表示法:直角座標和極座標。 如果我們選擇直角座標的表示法,那麼類的每個實例都將包含兩個字段,這兩個字段代表了對應點的xy

 

 

If p1 is the point shown, getting its x or its y simply requires looking up the corresponding field in this structure. Getting r or q, however, requires a computation: for r we must compute  , and for q we must compute arctg (y/x) with non-zero x.

如果p1是這樣的點,那麼簡單地從這個結構中查詢相關的字段就可以得到xy。然而,要得到rq需要一些計算:對於r,我們需要計算 ,要得到q我們需要計算非零xarctg (y/x)

 

If we use polar representation, the situation is reversed: r and q are now accessible by simple field lookup, x and y require small computations (of r cos q and r sin q).

如果我們使用極座標表示法,情況正好相反:簡單地字段查詢就可以得到rq,要得到xy需要一些小小的計算(r cos qr sin q)。

 

 

This example shows the need for two kinds of feature:

這個例子展示了對兩種特性的需求:

 

• Some features will be represented by space, that is to say by associating a certain piece of information with every instance of the class. They will be called attributes. For points, x and y are attributes in cartesian representation; rho and theta are attributes in polar representation.

·一些特性根據空間來表示,也就是說,根據類的每一個實例所關聯的特定信息。它們被稱之爲屬性(attributes。拿點來說,xy就是直角座標表示法的屬性;rhotheta是極座標表示法中的屬性。

 

• Some features will be represented by time, that is to say by defining a certain computation (an algorithm) applicable to all instances of the class. They will be called routines. For points, rho and theta are routines in cartesian representation; x and y are routines in polar representation.

·一些特性根據時間來表示,也就是說,根據定義一個特定的計算(一個運算法則)應用到類的所有實例上。它們被稱之爲例程(routines。拿點來說,rhotheta直角座標表示法的例程;xy是極座標表示法中的例程。

 

A further distinction affects routines (the second of these categories). Some routines will return a result; they are called functions. Here x and y in polar representation, as well as rho and theta in cartesian representation, are functions since they return a result, of type REAL. Routines which do not return a result correspond to the commands of an ADT specification and are called procedures. For example the class POINT will include procedures translate, rotate and scale.

一個更深的差別影響着例程(第二個種類)。某些例程有着返回值;它們被稱之爲函數(functions。這裏極座標表示法中的xy,連同直角座標表示法中的rhotheta,由於都有着類型REAL的返回值,所以都是函數。不帶有返回值的例程符合ADT規格中的命令,並被稱爲過程(procedures。比如,類POINT包括了過程translaterotatescale

 

Be sure not to confuse the use of “function” to denote result-returning routines in classes with the earlier use of this word to denote the mathematical specifications of operations in abstract data types. This conflict is unfortunate, but follows from well-established usage of the word in both the mathematics and software fields.

請務必不要混淆,在類中函數用於表示有返回結果的例程,這個詞的早期用法是在抽象數據類型中表示運算的數學規格。這種衝突是不幸的,但我們只能跟隨在數學和軟件領域中這個詞的習慣用法。

 

The following tree helps visualize this classification of features:

下面的樹形象化了這個特性的分類:

 

 

This is an external classification, in which the principal question is how a feature will look to its clients (its users).

這是一個外分類,在其中主要的問題是一個特性如何看待它的客戶(它的用戶)。

 

We can also take a more internal view, using as primary criterion how each feature is implemented in the class, and leading to a different classification:

我們也能夠從內部觀察,使用一個基本的標準:每個特性在類中如何被實現,這導致了一個不同的分類:

 

Uniform access

統一存取

 

One aspect of the preceding classifications may at first appear disturbing and has perhaps caught your attention. In many cases, we should be able to manipulate objects, for example a point p1, without having to worry about whether the internal representation of p1 is cartesian, polar or other. Is it appropriate, then, to distinguish explicitly between attributes and functions?

上述分類中的一個地方最初出現了些混亂。您也可能注意到了。許多情況下,我們應該能夠操作象點p1這樣的對象,並不需要考慮其內部表達形式直角座標,極座標還是其它。那麼,把屬性和函數之間明確地區別開來正確嗎?

 

The answer depends on whose view we consider: the supplier’s view (as seen by the author of the class itself, here POINT) or the client’s view (as seen by the author of a class that uses POINT). For the supplier, the distinction between attributes and functions is meaningful and necessary, since in some cases you will want to implement a feature by storage and in others by computation, and the decision must be reflected somewhere. What would be wrong, however, would be to force the clients to be aware of the difference. If I am accessing p1, I want to be able to find out its x or its r without having to know how such queries are implemented.

復取決於我們採用誰的觀點:應者的觀點(POINT類作者自己本身所瞭解的或客戶的觀點(POINT類的使用者所瞭解的)。對於供應者來說,屬性和函數之間的區別是有意義並且是必要的,因爲在某些情況下您想要由存儲來實現一個特性,在其它的情況下由計算來實現特性,並且這些決定必須在某些地方反映出來。然而,要強迫戶(clients知道這些區別卻是錯誤的。如果我正在訪問p1我想要能得到它的xr,而不必知道這樣的查詢是如何被實現的。

 

The Uniform Access principle, introduced in the discussion of modularity, answers this concern. The principle states that a client should be able to access a property of an object using a single notation, whether the property is implemented by memory or by computation (space or time, attribute or routine). We shall follow this important principle in devising a notation for feature call below: the expression denoting the value of the x feature for p1 will always be

p1.x

whether its effect is to access a field of an object or to execute a routine.

統一存取原則回答了這個問題,這在模塊性的討論中已經介紹過了。則闡明瞭客戶應該能使用一個單一的符號來訪問對象的屬性,不管屬性由存儲實現或由計算實現間或時間,屬性或例程對下面的特性調用們應該遵循這項重要原則來構想一個符號:表達式表示p1x特性的值總是爲

p1.x

不管它的作用是訪問對象的一個字段還是執行一個例程。

 

As you will have noted, the uncertainty can only exist for queries without arguments, which may be implemented as functions or as attributes. A command must be a procedure; a query with arguments must be a function, since attributes cannot have arguments.

您要注意了,不確定性只可能存在於沒有參數的查詢,這個查詢也許作爲函數或是屬性來實現。一個命令必須是一個過程;由於屬性不可能有參數,所以一個具有參數的詢問肯定是函數。

 

The Uniform Access principle is essential to guarantee the autonomy of the components of a system. It preserves the class designer’s freedom to experiment with various implementation techniques without disturbing the clients.

統一存取原則對保證系統的組件自治是非常必要的。它保護類設計者可以自由試驗各種各樣的實現技術,而不會干擾客戶。

 

Pascal, C and Ada violate the principle by providing a different notation for a function call and for an attribute access. For such non-object-oriented languages this is understandable (although we have seen that Algol W, a 1966 predecessor to Pascal, satisfied uniform access). More recent languages such as C++ and Java also do not enforce the principle. Departing from Uniform Access may cause any internal representation change (such as the switch from polar to cartesian or some other representation) to cause upheaval in many client classes. This is a primary source of instability in software development.

PascalCAda過對函數調用和對屬性存取提供了兩個不同的符號而違犯了這項原則。對這樣的非面嚮對象語言,這是可理解的儘管我們看到了Algol W,一個Pascal 1966年的早期版本,滿足了統一存取原則)。最近的語言例如C++Java也沒有強制執行此項原則。違反統一存取原則可能導致所有的內部表達形式上的變動例如座標轉換到直角座標或是某些其它的表示法進而引發在許多客戶類上的劇變。在軟件開發中這是不穩定性的主要源頭。

 

The Uniform Access principle also yields a requirement on documentation techniques. If we are to apply the principle consistently, we must ensure that it is not possible to determine, from the official documentation on a class, whether a query without arguments is a function or an attribute. This will be one of the properties of the standard mechanism for documenting a class, known as the short form.

統一存取原則在文檔技術上也有着一個要求。如果我們自始至終地運用這項原則,那麼我們必須保證從類的正式文檔開始就不可能要去確定沒有參數的查詢是否是函數還是屬性。這是制定類文檔的標準機制的屬性之一。

 

The class

 

Here is a version of the class text for POINT. (Any occurrence of consecutive dashes -- introduces a comment, which extends to the end of the line; comments are explanations intended for the reader of the class text and do not affect the semantics of the class.)

這裏有POINT類代碼的一個版本。(任何連續的破折號--都是註釋,一直延續到一行的末尾;註釋是解釋給代碼文本的讀者看的,並不影響類的語義。)

indexing

description: "Two-dimensional points"

class POINT feature

x, y: REAL

-- Abscissa and ordinate

rho: REAL is

-- Distance to origin (0, 0)

do

Result := sqrt (x ^ 2 + y ^ 2)

end

theta: REAL is

-- Angle to horizontal axis

do

¼Left to reader (exercise E7.3, page 216) º

end

distance (p: POINT): REAL is

-- Distance to p

do

Result := sqrt ((x – p lx) ^ 2 + (y – p l y) ^ 2)

end

translate (a, b: REAL) is

-- Move by a horizontally, b vertically.

do

x := x + a

y := y + b

end

scale (factor: REAL) is

-- Scale by factor.

do

x := factor S x

y := factor S y

end

rotate (p: POINT; angle: REAL) is

-- Rotate around p by angle.

do

¼Left to reader (exercise E7.3, page 216) ¼

end

end

 

The next few sections explain in detail the non-obvious aspects of this class text.

隨後的幾個小節將詳細解釋這段類代碼中的不易理解的部分。

 

The class mainly consists of a clause listing the various features and introduced by the keyword feature. There is also an indexing clause giving general description information, useful to readers of the class but with no effect on its execution semantics. Later on we will learn three optional clauses: inherit for inheritance, creation for nondefault creation and invariant for introducing class invariants; we will also see how to include two or more feature clauses in one class.

類主要由一個子句(clause)組成,子句列出了各種特性,並由關鍵字feature引出。這裏同時有一個indexing子句,給出了一般性的description信息,這對類的讀者很有用卻不影響執行語義。稍後,我們將學習三種可選子句:inherit繼承,creation非省缺創建符,和invariant類不變量;我們也將會看到如何在一個類中包含兩個或更多feature子句。

 

7.6 BASIC CONVENTIONS

7.6 基本約定

 

Class POINT shows a number of techniques which will be used throughout later examples. Let us first look at the basic conventions.

POINT展示了許多將在後面的例子中被使用的技術。讓我們先看一下基本的約定。

 

Recognizing feature kinds

瞭解特性的種類

 

Features x and y are just declared as being of type REAL, with no associated algorithm; so they can only be attributes. All other features have a clause of the form

is

do

¼ Instructions¼

end

which defines an algorithm; this indicates the feature is a routine. Routines rho, theta and distance are declared as returning a result, of type REAL in all cases, as indicated by declarations of the form

rho: REAL is ¼

特性xy只是聲明爲類型REAL的要素,並沒有關聯的算法;因此,它們只能是屬性。所有其它的特性都有一個如下形式的子句

is

do

¼ Instructions¼

end

其定義了一個算法;這表明了此特性是一個例程。例程rhothetadistance聲明返回一個結果,所有的結果都是類型REAL,聲明爲如下形式

rho: REAL is ¼

 

This defines them as functions. The other two, translate and scale, do not return a result (since they do not have a result declaration of the form :T for some type T), and so they are procedures.

這種形式把它們定義成函數。其它的兩個translatescale並沒有返回一個結果(這是因爲它們沒有聲明爲:T形式的結果,T是某種類型),因此,它們是過程。

 

Since x and y are attributes, while rho and theta are functions, the representation chosen in this particular class for points is cartesian.

由於xy是屬性,而rhotheta是函數,所以在這裏類所用的表示法是直角座標表示法。

 

Routine bodies and header comments

例程主體和頭註釋

 

The body of a routine (the do clause) is a sequence of instructions. You can use semicolons, in the Algol-Pascal tradition, to separate successive instructions and declarations, but the semicolons are optional. We will omit them for simplicity between elements on separate lines, but will always include them to delimit instructions or declarations appearing on the same line.

例程(do子句)的主體是一段連續的指令。在Algol-Pascal的語法中,您能夠使用分號來分割連續的指令和聲明,但分號是可選的。爲了簡單,在不同的行中我們可以省略分號,但是如果在同一行中,我們始終要使用這個符號來分割指令或聲明。

 

All the instructions in the routines of class POINT are assignments; for assignment, the notation uses the := symbol (again borrowed from the Algol-Pascal conventions). This symbol should of course not be confused with the equality symbol =, used, as in mathematics, as a comparison operator.

POINT例程中的所有指令都是賦值;對於賦值,符號使用了:=(再一次從Algol-Pascal語法中借用)。當然,這個符號不要和等於號=混淆,等於號在數學或比較運算符中使用。

 

Another convention of the notation is the use of header comments. As already noted, comments are introduced by two consecutive dashes --. They may appear at any place in a class text where the class author feels that readers will benefit from an explanation. A special role is played by the header comment which, as a general style rule, should appear at the beginning of every routine, after the keyword is, indented as shown by the examples in class POINT. Such a header comment should tersely express the purpose of the routine.

另一個符號的約定是頭註釋的使用。我們已經注意到了,註釋採用了兩個連續的短橫--。它們可以在類代碼中的任何地方出現,在那裏類的作者認爲讀者可以從解釋中受益。作爲一個通用風格的規則,頭註釋header comment)有着一個特別的作用,它將出現在每個例程的開頭,在關鍵字is之後,在類POINT的例子中顯示的縮進部分。這樣的一個頭註釋簡要地表達了例程的目的。

 

Attributes should also have a header comment immediately following their declaration, aligned with routine’s header comments, as illustrated here with x and y.

屬性也會有一個頭註釋緊接着它們的聲明之後,和例程的頭註釋對齊,就象在xy裏所展示的那樣。

 

The indexing clause

indexing子句

 

At the beginning of the class comes a clause starting with the keyword indexing. It contains a single entry, labeled description. The indexing clause has no effect on software execution, but serves to associate information with the class. In its general form it contains zero or more entries of the form

index_word: index_value, index_value, ¼

where the index_word is an arbitrary identifier, and each index_value is an arbitrary language element (identifier, integer, string¼).

在類的開頭有一個由關鍵字indexing開始的子句。它包含了一個標註爲description的單行。在軟件執行時indexing子句並不起作用,而是起着類信息的作用。在它的一般形式中它包含零個或多個index_word: index_value, index_value, ¼形式的項,其中index_word是一個任意的標識符,每一個index_value是一個任意的語言元素(標識符,整數,字符串

 

The benefit is twofold:

它的好處是兩方面的:

 

• Readers of the class get a summary of its properties, without having to see the details.

·類的讀者不用看細節就可以得到屬性的概要。

 

• In a software development environment supporting reuse, query tools (often known as browsers) can use the indexing information to help potential users find out about available classes; the tools can let the users enter various search words and match them with the index words and values.

·在一個支持複用的軟件開發環境中,查詢工具(如browsers)能夠使用indexing信息去幫助潛在的用戶找到可用的類;工具能夠讓用戶輸入各種各樣的查找關鍵字,並與索引字和索引值匹陪。

 

The example has a single indexing entry, with description as index word and, as index value, a string describing the purpose of the class. All classes in this book, save for short examples, will include a description entry. You are strongly encouraged to follow this example and begin every class text with an indexing clause providing a concise overview of the class, in the same way that every routine begins with a header comment.

例子裏有一個單獨的索引項,以description作爲索引字,並且用一個描述類的目的的字符串作爲索引值。本書中除了一些精簡的例子之外所有的類都將包括description項。我強烈地建議您照這個例子做,在每個類代碼中以indexing子句開始,來提供一個簡明的類描述,同樣地每一個例程也以一個頭註釋開始。

 

Both indexing clauses and header comments are faithful applications of the Self-Documentation principle: as much as possible of a module’s documentation should appear in the text of the module itself.

索引子句和頭註釋都是自包含文檔則的正確應用:一個模塊的文檔儘可能應該出現在模塊代碼的自身當中。

 

Denoting a function’s result

指明函數的返回值

 

We need another convention to understand the texts of the functions in class POINT: rho, theta and distance.

我們需要另一個約定來理解類POINT中函數的代碼:rhothetadistance

 

Any language that supports functions (value-returning routines) must offer a notation allowing the body of a function to set the value which will be returned by any particular call. The convention used here is simple: it relies on a predefined entity name, Result, denoting the value that the call will return. For example, the body of rho contains an assignment to Result:

Result := sqrt (x ^ 2 + y ^ 2)

任何支持函數(有着返回值的例程)的語言必須提供一個符號來允許一個函數體設置返回值,這個返回值將返回給任何正規的調用。這裏的約定很簡單:它依靠預先設定的實體名字Result,表示將返回的值。例如,rho的函數體包含了一個Result的賦值:

Result := sqrt (x ^ 2 + y ^ 2)

 

Result is a reserved word, and may only appear in functions. In a function declared as having a result of type T, Result is treated in the same way as other entities, and may be assigned values through assignment instructions such as the above.

Result是一個保留關鍵字,並且只可能出現在函數中。在一個函數中Result被聲明爲一個類型T的返回結果,和其它的實體一樣對待,並且可以象上面一樣通過賦值指令來賦值。

 

Any call to the function will return, as its result, the final value assigned to Result during the call’s execution. That value always exists since language rules (to be seen in detail later) require every execution of the routine, when it starts, to initialize Result to a preset value. For a REAL the initialization value is zero; so a function of the form

non_negative_value (x: REAL): REAL is

-- The value of x if positive; zero otherwise.

do

if x > 0.0 then

Result := x

end

end

will always return a well-defined value (as described by the header comment) even though the conditional instruction has no else part.

任何調用函數都將返回最終值作爲其結果,最終值是在調用的執行中賦給Result的。由於語言的規則要求(後面會瞭解到細節)每一個例程在開始執行的時候用一個預定義的值來初始化Result,所以這個值總是存在。對於一個REAL,初始化值是零;因此下列的函數

non_negative_value (x: REAL): REAL is

-- The value of x if positive; zero otherwise.

do

if x > 0.0 then

Result := x

end

end

將總是返回一個定義明確的值(與頭註釋裏描述一樣),即使條件指令沒有else部分。

 

The discussion section of this chapter examines the rationale behind the Result convention and compares it with other techniques such as return instructions. Although this convention addresses an issue that arises in all design and programming languages, it blends particularly well with the rest of the object-oriented approach.

本章的討論部分會分析約定Result背後的理論基礎,並與其它的技術相比較,例如返回指令。雖然這個約定致力於在所有的設計和編程語言中出現問題,但是它特別地和其它的面向對象方法工作得很好。

 

Style rules

式樣規則

 

The class texts in this book follow precise style conventions regarding indentation, fonts (for typeset output), choice of names for features and classes, use of lower and upper case.

本書中的類代碼採用了簡明的式樣約定,如縮進,字體(排版輸出),特性和類命名的選擇,大小字母的使用等等。

 

The discussion will point out these conventions, under the heading “style rules”, as we go along. They should not be dismissed as mere cosmetics: quality software requires consistency and attention to all details, of form as well as of content. The reusability goal makes these observations even more important, since it implies that software texts will have a long life, during which many people will need to understand and improve them.

在標題式樣規則”引導討論中將會指出這些約定。應該僅僅因爲裝飾作用就拒絕它們:高質量的軟件要求一致性並注意所有細節,對待形式就和對待內容一樣。用性的目標使這些要求更加重要,因爲它暗示軟件代碼將有着較長的壽命,在這個期間許多人將需要了解並改進它們。

 

You should apply the style rules right from the time you start writing a class. For example you should never write a routine without immediately including its header comment. This does not take long, and is not wasted time; in fact it is time saved for all future work on the class, whether by you or by others, whether after half an hour or after half a decade. Using regular indentation, proper spelling for comments and identifiers, adequate lexical conventions — a space before each opening parenthesis but not after, and so on — does not make your task any longer than ignoring these rules, but compounded over months of work and heaps of software produces a tremendous difference. Attention to such details, although not sufficient, is a necessary condition for quality software (and quality, the general theme of this book, is what defines software engineering).

應該從一開始就運用樣式規則。例如您從不應該編寫沒有包括頭註釋的例程。這並不花費很多時間,也並不浪費時間實際上對於往後的工作這是節省時間,不論是對您或是對別人,不論是在半小時以後或是在五年之後。使用適當的縮進、正確的註釋和標識符的拼寫,充分的詞彙約定——在每個開頭括號之前而不是在之後的一個格,等等——並不會使您的工作比忽略這些規則花費更長的時間,但是在混合了幾個月的工作和大量的代碼之後會使產生一個巨大的差異。雖然並不充分,但是注重這樣的細節卻是一個軟件品質的必要條件這就是軟件工程所定義的品質,也是本書的主題

 

The elementary style rules are clear from the preceding class example. Since our immediate goal is to explore the basic mechanisms of object technology, their precise description will only appear in a later chapter.

在先前的類例子中基本的樣式規則很清楚。由於我們的當前目標是探索對象技術的基本機制,所以它們的精確描述將會出現於後面的章節中。

 

Inheriting general-purpose facilities

從多用途的工具類中繼承

 

Another aspect of class POINT which requires clarification is the presence of calls to the sqrt function (in rho and distance). This function should clearly return the square root of a real number, but where does it come from?

POINT中需要澄清的另一個方面是調用中出現的sqrt函數(在rhodistance裏面)。這個函數很明顯地應該返回一個實數的平方根,但是它是哪裏來的呢?

 

Since it does not seem appropriate to encumber a general-purpose language with specialized arithmetic operations, the best technique is to define such operations as features of some specialized class — say ARITHMETIC — and then simply require any class that needs these facilities to inherit from the specialized class. As will be seen in detail in a later chapter, it suffices then to write POINT as

class POINT inherit

ARITHMETIC

feature

¼ The rest as before ¼

end

由於系統並沒有排斥一個帶有特殊數學運算的多用途語言,所以最好的技術就是定義這樣的運算作爲某個特殊類的特性,這個類假定爲ARITHMETIC ,並且簡單地要求任何需要這些運算的類從這個特殊類中繼承。把POINT定義爲

class POINT inherit

ARITHMETIC

feature

¼ The rest as before ¼

end

在後面的章節中我們將會詳細地瞭解。

 

This technique of inheriting general-purpose facilities is somewhat controversial; one can argue that O-O principles suggest making a function such as sqrt a feature of the class representing the object to which it applies, for example REAL. But there are many operations on real numbers, not all of which can be included in the class. Square root may be sufficiently fundamental to justify making it a feature of class REAL; then we would write a.sqrt rather than sqrt (x). We will return, in the discussion of design principles, to the question of whether “facilities” classes such as ARITHMETIC are desirable.

這個從多用途工具類中繼承的技術有着一些爭議;一個爭論是OO原則建議了定義一個象sqrt這樣的函數,作爲其應用的對象的類的一個特性,如類REAL。但是在實數中有這許多的運算,不是所有的都能包含在類中。平方根也許足夠基本來成爲類REAL的一個特性;接着我們將使用a.sqrt,而不是sqrt (x)。在設計原則的討論中,我們將回到象ARITHMETIC這樣的“工具”類是否值得的問題上來。

 

7.7 THE OBJECT-ORIENTED STYLE OF COMPUTATION

7.7 計算的面向對象式樣

 

Let us now move to the fundamental properties of class POINT by trying to understand a typical routine body and its instructions, then studying how the class and its features may be used by other classes — clients.

現在讓我們轉到類POINT的基本屬性上來,我們要試着理解一個典型的例程體和它的指令,接着研究類和其特性如何可以被其它類——客戶——所使用。

 

The current instance

當前實例

 

Here again is the text of one of our example routines, procedure translate:

這裏再次使用的是我們例子中的一個例程的代碼,過程translate

translate (a, b: REAL) is

-- Move by a horizontally, b vertically

do

x := x + a

y := y + b

end

 

At first sight this text appears clear enough: to translate a point by a horizontally, b vertically, we add a to its x and b to its y. But if you look at it more carefully, it may not be so obvious anymore! Nowhere in the text have we stated what point we were talking about. To whose x and whose y are we adding a and b? In the answer to this question will lie one of the most distinctive aspects of the object-oriented development style. Before we are ready to discover that answer we must understand a few intermediate topics.

剛看到這段代碼會覺得很清楚:通過水平增量a和垂直增量b移動一個點,我們把點的x加上a,點的y加上b。但是如果您再仔細看看,也許並不那麼顯而易見!代碼中並沒有任何地方聲明瞭我們正在談論的點。我們要把ab加到哪一個點的xy上?此問題的答案將展現一個面向對象開發式樣中最與衆不同的方面。在我們獲得答案之前,我們必須要理解一些中間的主題。

 

A class text describes the properties and behavior of objects of a certain type, points in this example. It does so by describing the properties and behavior of a typical instance of that type — what we could call the “point in the street” in the way newspapers report the opinion of the “man or woman in the street”. We will settle for a more formal name: the current instance of the class.

類代碼描述了一個特定類型的對象的屬性和行爲,在本例中這個類型是點。它通過描述那個類型的一個典型實例的屬性和行爲來做到這一點——報紙把我們稱之爲在街上的”的觀點叫做“在街上的人們們將接受一個更加正式的名字:類的當前實例(current instance

 

Once in a while, we may need to refer to the current instance explicitly. There served word

Current

will serve that purpose. In a class text, Current denotes the current instance of the enclosing class. As an example of when Current is needed, assume we rewrite distance so that it checks first whether the argument p is the same point as the current instance, in which case the result is 0 with no need for further computation. Then distance will appear as

distance (p: POINT): REAL is

-- Distance to p

do

if p /= Current then

Result := sqrt ((x — p.x) ^ 2 + (y — p.y) ^ 2)

end

end

(/= is the inequality operator. Because of the initialization rule mentioned above, the conditional instruction does not need an else part: if p = Current the result is zero.)

偶爾,我們也許需要明確地引用當前的實例。保留關鍵字Current就是用於這個目的。在類的代碼中,Current表示外圍類(enclosing class)的當前實例。舉一個什麼時候需要Current的例子,假定我們重寫distance,想讓它先檢查參數p和當前實例是否是同樣的點,如果結果是零就不需要進一步的計算了。那麼distance顯示如下

distance (p: POINT): REAL is

-- Distance to p

do

if p /= Current then

Result := sqrt ((x — p.x) ^ 2 + (y — p.y) ^ 2)

end

end

/=是不等運算符。因爲上面所提及的初始化規則,條件指令並不需要else部分:如果p = Current,結果爲零。)

[]enclosing class有的書上叫做封閉類,我採用了侯捷的譯法。

 

In most circumstances, however, the current instance is implicit and we will not need to refer to Current by its name. For example, references to x in the body of translate and the other routines simply mean, if not further qualified: “the x of the current instance”.

然而,在絕大部分的情況中,當前的實例是隱含的,我們不需要通過它的名字來引用Current。比如,在translate的函數體和其它例程中的x引用簡單地意味着,如果沒有進一步的限定,就是“當前實例的x”。

 

This only pushes back the mystery, of course: “who” really is Current? The answer will come with the study of routine calls below. As long as we only look at the routine text, it will suffice to know that all operations are relative, by default, to an implicitly defined object, the current instance.

只剩下一個祕密了,就是:Current到底是“誰”?答案將隨着下面的例程調用的學習而浮現出來。在我們只考慮例程代碼的時候,就足以知道在缺省的情況下,所有的運算都關聯到一個隱含的定義對象:當前的實例。

 

Clients and suppliers

客戶和供應者

 

Ignoring for a few moments the enigma of Current’s identity, we know how to define simple classes. We must now study how to use their definitions. Such uses will be in other classes — since in a pure object-oriented approach every software element is part of some class text.

暫時把Current特徵之迷放在一邊,我們知道了如何定義簡單的類。現在我們應當研究如何使用它們的定義。這樣的用法將會出現在其它的類中——這是由於在一個純粹的面向對象的方法中每一個軟件元素都是某個類代碼的一部分。

 

There are only two ways to use a class such as POINT. One is to inherit from it; this is studied in detail in later chapters. The other one is to become a client of POINT.

這裏只有兩種方法來使用諸如POINT這樣的類。一種是繼承;細節將在隨後的章節中研究。另一種是成爲POINT客戶client)。

 

The simplest and most common way to become a client of a class is to declare an entity of the corresponding type:

要成爲類的一個客戶,最簡單和最常用的方法是聲明一個對應類型的實體:

 

Definition: client, supplier

Let S be a class. A class C which contains a declaration of the form a: S is said to be a client of S. S is then said to be a supplier of C.

定義:客戶,供應者

S爲一個類。包含一個a: S形式的聲明的類C被稱之爲S的客戶。那麼,S被稱之爲C的供應者。

 

In this definition, a may be an attribute or function of C, or a local entity or argument of a routine of C.

在這個定義中,a也許是C的一個函數或特性,或者是C的例程的一個局部實體或參數。

 

For example, the declarations of x, y, rho, theta and distance above make class POINT a client of REAL. Other classes may in turn become clients of POINT. Here is an example:

舉個例子,上面的xyrhothetadistance聲明使得類POINT成爲REAL的一個客戶。其它的類依此成爲POINT的客戶。舉例如下:

 

class GRAPHICS feature

p1: POINT

¼

some_routine is

-- Perform some actions with p1.

do

¼ Create an instance of POINT and attach it to p1 ¼

p1.translate (4.0, –1.5) --SS

¼

end

¼

End

 

Before the instruction marked --SS gets executed, the attribute p1 will have a value denoting a certain instance of class POINT. Assume that this instance represents the origin, of coordinates x = 0, y = 0:

在帶有--SS註釋的指令執行之前,屬性p1將有一個值表示類POINT的一個特定實例。假設這個實例表示了座標爲x = 0y = 0的原點:

 

 

Entity p1 is said to be attached to this object. We do not worry at this point about how the object has been created (by the unexplained line that reads “¼Create object¼”) and initialized; such topics will be discussed as part of the object model in the next chapter. Let us just assume that the object exists and that p1 is attached to it.

實體p1被稱之爲附屬(attached在這個對象上。此時我們不用擔心對象如何被創建(¼Create¼註釋行)和初始化;這個主題會在下一章中的對象模型部分中討論。讓我們只是假定對象存在並且p1附屬其上。

 

Feature call

特性調用

 

The starred instruction,

p1.translate (4.0, –1.5)

deserves careful examination since it is our first complete example of what may be called the basic mechanism of object-oriented computation: feature call. In the execution of an object-oriented software system, all computation is achieved by calling certain features on certain objects.

由於這是我們用第一個完整的例子來研究什麼是面向對象計算的基本機制(basic mechanism of object-oriented computation):特性調用,所以主要的指令p1.translate (4.0, –1.5)應該仔細地分析。在一個面向對象軟件系統的執行中,所有的計算都是在一定的對象上調用某些特性來完成的。

 

This particular feature call means: apply to p1 the feature translate of class POINT, with arguments 4.0 and –1.5, corresponding to a and b in the declaration of translate as it appears in the class. More generally, a feature call appears in its basic form as one of

x.f

x.f (u, v, ¼)

這個特別的特性調用意思爲:將類POINT的特性translate應用到p1上,並帶有參數4.0–1.5,參數對應於類中定義的translate聲明中的ab。通常,一個特性調用所表現的基本形式是下面的一種:

x.f

x.f (u, v, ¼)

 

In such a call, x, called the target of the call, is an entity or expression (which at run time will be attached to a certain object). As any other entity or expression, x has a certain type, given by a class C; then f must be one of the features of C. More precisely, in the first form, f must be an attribute or a routine without arguments; in the second form, f must be a routine with arguments, and u, v, ¼, called the actual arguments for the call, must be expressions matching in type and number the formal arguments declared for f in C.

在這種調用中,x稱做調用的目標(target,它是一個實體或是表達式(其在運行的時候將會附屬在某個對象上)。與任何其它的實體或表達式一樣,類C給予了x一個固定的類型;於是f必須是C的特性之一。更精確地說,在第一個形式中,f必須是一個屬性或是一個不帶參數的特性;在第二個形式中,f必須是一個帶有參數的例程,其中uv叫做實際參數(實參actual arguments),它們必須要匹配C中的f所聲明的形式參數類型和個數。

 

In addition, f must be available (exported) to the client containing this call. This is the default; a later section will show how to restrict export rights. For the moment, all features are available to all clients.

另外,f必須對有此調用的客戶有效(輸出)。這是默認的;後面的部分將展示如何限制輸出的權限。此刻,所有的特性對所有的客戶都有效。

 

The effect of the above call when executed at run time is defined as follows:

在運行的時候,上述調用執行的實現定義如下:

 

Effect of calling a feature f on a target x

Apply feature f to the object attached to x, after having initialized each formal argument of f (if any) to the value of the corresponding actual argument.

在目標x上調用特性f的實現

在把每一個f的形參(如果有的話)初始化成對應的實參值之後,調用賦屬在x上的對象的特性f

 

 

The Single Target principle

單一目標原則

 

What is so special about feature call? After all, every software developer knows how to write a procedure translate which moves a point by a certain displacement, and is called in the traditional form (available, with minor variants, in all programming languages):

translate (p1, 4.0, –1.5)

什麼是特性調用的特殊性?畢竟,每一個軟件開發者都知道如何編寫一個經過一個確定的偏移來移動一個點的過程,這個過程的傳統調用形式(除了很小的一些變化之外,在所有的編程語言中都適用):

translate (p1, 4.0, –1.5)

 

Unlike the object-oriented style of feature call, however, this call treats all arguments on an equal basis. The O-O form has no such symmetry: we choose a certain object (here the point p1) as target, relegating the other arguments, here the real numbers 4.0 and –1.5, to the role of supporting cast. This way of making every call relative to a single target object is a central part of the object-oriented style of computing:

然而,不同於特性調用的面向對象方式,這個調用在一個平等的基礎上對待所有的參數。OO形式沒有這樣的對稱性:我們選擇一個確定的對象(這兒是點p1)爲目標,把其它的參數,這裏是實數4.0–1.5,歸類到支持計算的角色。這種讓每個調用關係到一個單一目標對象的方式是面向對象計算式樣的核心部分:

 

Single Target principle

Every operation of object-oriented computation is relative to a certain object, the current instance at the time of the operation’s execution.

單一目標原則
面向對象計算的每一個運算都關聯到一個特定的對象上,這是運算執行的時候當前的對象實例。

 

To novices, this is often the most disconcerting aspect of the method. In object-oriented software construction, we never really ask: “Apply this operation to these objects”. Instead we say: “Apply this operation to this object here.” And perhaps (in the second form): “Oh, by the way, I almost forgot, you will need those values there as arguments”.

對於新手來說,這常常是最令人糊塗的部分。在面向對象軟件架構中,我們從不說:“把這個運算應用到這些對象上”。而是說:“應用此運算到這個this)對象上。”同時,也許說(第二種形式):“哦,順便說一下,我幾乎忘了您需要那些值作爲參數”。

 

What we have seen so far does not really suffice to justify this convention; in fact its negative consequences will, for a while, overshadow its advantages. An example of counter-intuitive effect appears with the function distance of class POINT, declared above as distance (p: POINT): REAL, implying that a typical call will be written

p1.distance (p2)

which runs against the perception of distance as a symmetric operation on two arguments. Only with the introduction of inheritance will the Single Target principle be fully vindicated.

到目前爲止,我們所看到的並沒有真正地體現了這個約定的好處;事實上,它的消極作用暫時超過了它的益處。一個違背直覺的例子出現在了類POINT的函數distance中,上述的函數聲明爲distance (p: POINT): REAL,暗示着一個典型的調用將寫成p1.distance (p2),這違反了把distance看作是一個在兩個參數上的對稱運算的理解。只有隨着繼承的引進才能證明單一目標原則的正確性。

 

The module-type identification

模塊類型的驗證

 

The Single Target principle is a direct consequence of the module-type merge, presented earlier as the starting point of object-oriented decomposition: if every module is a type, then every operation in the module is relative to a certain instance of that type (the current instance). Up to now, however, the details of that merge remained a little mysterious. A class, it was said above, is both a module and a type; but how can we reconcile the syntactic notion of module (a grouping of related facilities, forming a part of a software system) with the semantic notion of type (the static description of certain possible runtime objects)? The example of POINT makes the answer clear:

單一目標原則是一個模塊融合的直接結果,早先是作爲面向對象分解性的起點而被介紹的:如果每個模塊都是一個類型,那麼每個在模塊中的運算都關聯到那個類型的某個實例(當前的實例)上。然而,到目前爲止,那個融合的細節仍然保留着一絲的神祕。如上所說,一個類既是一個模塊也是一個類型;但是我們如何能夠讓模塊的語法概念(一組相關的工具,一個軟件系統的組成部分)和類型的語義概念(某個可能的運行時對象的靜態描述)一致呢?POINT的例子清楚地得到了答案:

 

How the module-type merge works

The facilities provided by class POINT, viewed as a module, are precisely the operations available on instances of class POINT, viewed as a type.

模塊-類型的融合如何工作

POINT所提供的工具正好是類POINT的實例上的有效運算,把工具看做一個模塊,把實例看做一個類型。

 

This identification between the operations on instances of a type and the services provided by a module lies at the heart of the structuring discipline enforced by the object-oriented method.

在一個類型實例上的運算和一個模塊所提供的服務之間的辨識,存在於面向對象方式所推行的結構科學的核心中。

 

The role of Current

Current的作用

 

With the help of the same example, we are now also in a position to clear the remaining mystery: what does the current instance really represent?

在同一個例子的幫助下,我們現在也能夠明白剩下的神祕了:當前的實例真正代表了什麼?

 

The form of calls indicates why the text of a routine (such as translate in POINT) does not need to specify “who” Current is: since every call to the routine will be relative to a certain target, specified explicitly in the call, the execution will treat every feature name appearing in the text of the routine (for example x in the text of translate) as applying to that particular target. So for the execution of the call

p1.translate (4.0, –1.5)

every occurrence of x in the body of translate, such as those in the instruction

x := x + a

means: “the x of p1”.

調用的形式指出了爲什麼一個例程的代碼(如POINT中的translate)不需要指明Current是“誰”:由於每個例程的調用都將關聯到一個特定的目標上,這個目標在調用中已經明確地指明瞭,所以執行過程將把每一個出現在例程代碼中的特性名字(比如translate代碼中的x)認爲是應用到那個特別的目標上的。因此,對於調用p1.translate (4.0, –1.5)的執行來說,在translate代碼中出現的每個x,如在指令x := x + a中的那樣,都認爲是:“p1x”。

 

The exact meaning of Current follows from these observations. Current means: “the target of the current call”. For example, for the duration of the above call, Current will denote the object attached to p1. In a subsequent call, Current will denote the target of that new call. That this all makes sense follows from the extreme simplicity of the object-oriented computation model, based on feature calls and on the Single Target principle:

Current的準確意思是從這些結論中得來的。Current意思爲:“當前調用的目標”。譬如,上面調用的過程中,Current將代表附屬到p1的對象。在後面的調用中,Current將代表新調用的目標。所有這一切從面向對象計算模型的極端簡單性的根據而來的意義,都基於特性調用和單一目標原則:

 

Feature Call principle

F1 • No software element ever gets executed except as part of a routine call.

F2 • Every call has a target.

特性調用原則

F1·沒有軟件元素能在例程調用之外被執行。

F2·每一個調用都有一個目標。

 

Qualified and unqualified calls

限定的和非限定的調用

 

It was said above that all object-oriented computation relies on feature calls. A consequence of this rule is that software texts actually contain more calls than meet the eye at first. The calls seen so far were of one of the two forms introduced above:

x.f

x.f (u, v, ¼)

上面我們所說的是所有的面向對象計算方法都基於特性調用。此規則的一個後果是軟件代碼實際上包含有更多的調用,而不是我們剛開始所看到的那樣。到目前爲止,我們所知道的調用只是上面介紹的兩種形式中的一個:

x.f

x.f (u, v, ¼)

 

Such calls use so-called dot notation (with the “.” symbol) and are said to be qualified because the target of the call is explicitly identified: it is the entity or expression (x in both cases above) that appears before the dot.

這樣的調用使用了所謂的圓點符號(“.”),並且稱之爲限定的(qualified,因爲調用的目標是很顯然被確定了的:它是出現在圓點之前的實體或是表達式(上面兩種情況中的x)。

 

Other calls, however, will be unqualified because their targets are implicit. As an example, assume that we want to add to class POINT a procedure transform that will both translate and scale a point. The procedure’s text may rely on translate and scale:

然而,另外一種調用將是非限定的,因爲它們的目標並不明確。舉一個例子,假定我們要在類POINT中增加一個過程transform,這個過程將移動並繪製一個點。過程的代碼使用translatescale

transform (a, b, factor: REAL) is

-- Move by a horizontally, b vertically, then scale by factor.

do

translate (a, b)

scale ( factor)

end

 

The routine body contains calls to translate and scale. Unlike the earlier examples, these calls do not show an explicit target, and do not use dot notation. Such calls are said to be unqualified.

例程體包含有translatescale的調用。不象先前的例子,這些調用沒有出現一個明顯的目標,也沒有使用圓點符號。這樣的調用稱之爲非限定的(unqualified

 

Unqualified calls do not violate the property called F2 in the Feature Call principle: like qualified calls, they have a target. As you have certainly guessed, the target in this case is the current instance. When procedure transform is called on a certain target, its body calls translate and scale on the same target. It could in fact have been written

非限定的調用並沒有違法特性調用原則中的屬性調用F2:就象限定調用一樣,它們也有着目標。正如您猜到的,這個情況中目標就是當前的實例。當過程transform在一個特定的目標上被調用的時候,它的代碼在同一個目標上調用translatescale。事實上,它們可以寫成:

do

Current.translate (a, b)

Current.scale ( factor)

 

More generally, you may rewrite any unqualified call as a qualified call with Current as its target. The unqualified form is of course simpler and just as clear.

通常地,您可以重寫任何的非限定調用,帶上Current作爲它的目標變成一個限定調用。當然,非限定的形式更簡單,更清晰。

 

The unqualified calls that we have just examined were calls to routines. The same discussion applies to attributes, although the presence of calls is perhaps less obvious in this case. It was noted above that, in the body of translate, the occurrence of x in the expression x + a denotes the x field of the current instance. Another way of expressing this property is that x is actually a feature call, so that the expression as a whole could have been written as Current.x + a.

我們剛纔研究過的非限定調用是例程上的調用。雖然在這個例子中調用的出現並不明顯,但是同樣的討論將適用於屬性。如上所述,在translate體中,表達式x + a中的x表示了當前實例的x字段。表達這個屬性的另一種方法是x是一個事實上的特性調用,如此表達式可以完整地寫成Current.x + a

 

More generally, any instruction or expression of one of the forms

f

f (u, v, ¼)

is in fact an unqualified call, and you may also write it in qualified form as (respectively)

Current.f

Current.f (u, v, ¼)

although the unqualified forms are more convenient. If you use such a notation as an instruction, f must be a procedure (with no argument in the first form, and with the appropriate number and types of arguments in the second). If it is an expression, f may be an attribute (in the first form only, since attributes have no arguments) or a function.

事實上,下列兩者中的任何一個指令或者表達式都是一個非限定調用

f

f (u, v, ¼)

同時,雖然非限定形式更方便一些,但您也可以把它們對應地寫成限定的形式

Current.f

Current.f (u, v, ¼)

如果您使用這種符號當作一個指令,那麼f必須是一個過程(在第一種形式中沒有參數,在第二種中帶有適當數目和類型的參數)。如果f是一個表達式,它必須是一個屬性(只是針對第一種形式,這是由於屬性沒有參數)或是一個函數。

 

Be sure to note that this syntactical equivalence only applies to a feature used as an instruction or an expression. So in the following assignment from procedure translate

x := x + a

only the occurrence of x on the right-hand side is an unqualified call: a is a formal argument, not a feature; and the occurrence of x on the left is not an expression (one cannot assign a value to an expression), so it would be meaningless to replace it by Current.x.

要確信注意的是這個法只是等同於應用一個作爲一個指令或是表達式而使用的特性。因此,在下列的translate過程中的賦值語句中

x := x + a

只有x出現在右邊纔是一個非限定調用:a是一個形式參數,不是一個特性;x出現在左邊不是一個表達式(它不能賦一個值到表達式上),因此,把它置換成Current.x是無意義的。

 

Operator features

運算符特性

 

A further look at the expression x + a leads to a useful notion: operator features. This notion (and the present section) may be viewed as pure “cosmetics”, that is to say, covering only a syntactical facility without bringing anything really new to the object-oriented method. But such syntactical properties can be important to make developers’ life easier if they are present — or miserable if they are absent. Operator features also provide a good example of how successful the object-oriented paradigm can be at integrating earlier approaches smoothly.

更進一步地考慮表達式x + a,它引出了一個有用的符號:運算符特性。這個符號(和所表達的部分)也許被看作是純粹的“修飾”,也就是說,只是披着語法的外衣,而沒有給面向對象方法帶來任何新的東西。但是如果這種語法屬性存在的話,能夠顯著的讓開發者的工作更簡單——或者說沒有它們卻是非常的痛苦。運算符特性也提供了一個良好的範例,既面向對象樣式如何成功的順利結合早期的方法。

 

Here is the idea. Although you may not have guessed it, the expression x + a contains not just one call — the call to x, as just seen — but two. In non-O-O computation, we would consider + as an operator, applied here to two values x and a, both declared of type REAL. In a pure O-O model, as noted, the only computational mechanism is feature call; so you may consider the addition itself, at least in theory, to be a call to an addition feature.

這裏有一個想法。您也許沒有想到,表達式x + a並不僅僅包含一個調用——正如您看到的調用x ——而是兩個。在非OO的計算中,我們常把+考慮成一個運算符,這裏把兩個值xa相加,這兩個值都聲明成類型REAL。在一個純OO模型中,計算機制只是特性調用;因此至少在理論上,您可以把加法本身考慮成一個加法特性的調用。

 

To understand this better, consider how we could define the type REAL. The Object rule stated earlier implied that every type is based on some class. This applies to predefined types such as REAL as well as developer-defined types such as POINT. Assume you are requested to write REAL as a class. It is not hard to identify the relevant features: arithmetic operations (addition, subtraction, negation¼), comparison operations (less than, greater than¼). So a first sketch could appear as:

爲了更好地理解,請考慮我們如何定義類型REAL。先前的對象規則隱含地規定了每一種類型都基於某個類。這同時適用於如REAL這樣的預定義類型,也適用於如POINT這樣的開發者定義的(自定義的)類型。假設要求我們寫一個REAL類。確定相關的特性並不困難:算術運算(加,減,負),比較運算(小於,大於…)。初始框架如下:

indexing

description: "Real numbers (not final version!)"

class REAL feature

plus (other: REAL): REAL is

-- Sum of current value and other

do

¼

end

minus (other: REAL) REAL is

-- Difference of current value and other

do

¼

end

negated: REAL is

-- Current value but with opposite sign

do

¼

end

less_than (other: REAL): BOOLEAN is

-- Is current value strictly less than other?

do

¼

end

¼ Other features ¼

End

 

With such a form of the class, you could not write an arithmetic expression such as x + a any more; instead, you would use a call of the form

x.plus (a)

您不能用這樣的類形式寫出一個象x + a之類的算術表達式;您需要使用x.plus (a)這樣形式的調用。

 

Similarly, you would have to write x.negated instead of the usual –x.

同樣地,您需要使用x.negated,而不是平時所用的–x

 

One might try to justify such a departure from usual mathematical notation on the grounds of consistency with the object-oriented model, and invoke the example of Lisp to suggest that it is sometimes possible to convince a subset of the software development community to renounce standard notation. But this argument contains it owns limitations: usage of Lisp has always remained marginal. It is rather dangerous to go against notations which have been in existence for centuries, and which people have been using since elementary school, especially when there is nothing wrong with these notations.

以與面向對象模型保持一致爲理由而違背常用的數學符號,這件事情也許需要設法證明是對是錯,同時,借用LISP的例子來說明一些小的軟件開發團隊有的時候放棄標準的符號是極有可能的。但是這個根據有着自己的侷限性:LISP的用法總是會留下標記。違反幾百年來一直存在,並且人們自小就使用的符號這是相當危險的,尤其是這些符號並沒有什麼不對的地方。

 

A simple syntactical device reconciles the desire for consistency (requiring here a single computational mechanism based on feature call) and the need for compatibility with traditional notations. It suffices to consider that an expression of the form

x + a

is in fact a call to the addition feature of class REAL; the only difference with the plus feature suggested above is that we must rewrite the declaration of the corresponding feature to specify that calls will use operator notation rather than dot notation.

一個簡單的語法設計即協調了一致性的要求(這裏需要一個單一的基於特性調用的計算機制),也協調了與傳統符號兼容的需要。它滿足了一個x + a形式的表達式實際上是一個類REAL的加法特性的調用;唯一和上面建議的plus特性不同的是我們必須重寫對應特性的聲明,來指明調用將使用運算符而不是圓點符號。

 

Here is the form of a class that achieves this goal:

這裏是實現這個目的的類的形式:

 

indexing

description: "Real numbers"

class REAL feature

infix "+" (other: REAL): REAL is

-- Sum of current value and other

do

¼

end

infix "–" (other: REAL) REAL is

-- Difference of current value and other

do

¼

end

prefix "–": REAL is

-- Current value but with opposite sign

do

¼

end

infix "<" (other: REAL): BOOLEAN is

-- Is current value strictly less than other?

do

¼

end

¼ Other features ¼

End

 

Two new keywords have been introduced: infix and prefix. The only syntactical extension is that from now on we may choose feature names which, instead of identifiers (such as distance or plus), are of one of the two forms

infix "§"

prefix "§"

where § stands for an operator symbol chosen from a list which includes +, , S, <, <= and a few other possibilities listed below. A feature may have a name of the infix form only if it is a function with one argument, such as the functions called plus, minus and less_than in the original version of class REAL; it may have a name of the prefix form only if it is a function with no argument, or an attribute.

介紹兩個新的關鍵字:infixprefix。從現在開始,最好的語法選擇範圍是,我們可以選擇用以下兩種形式之一來命名的特性,而不是標識符(如distanceplus

infix "§"

prefix "§"

這裏的§代表着一個運算符號,選自於包括+S<<=和其它的一些可能的符號的列表。一個特性可以有一個infix格式的名字,如果它只是一個帶有一個參數的函數,如在類REAL原始版本中的plusminusless_than函數;它也可以有一個prefix格式的名字,如果它只是一個不帶有參數的函數,或是一個屬性。

 

Infix and prefix features, collectively called operator features, are treated exactly like other features (called identifier features) with the exception of the two syntactical properties already seen:

Infixprefix特性,叫做運算符特性(operator features,除了已經知道的兩個語法屬性以外,它們等同於其它的特性(叫做標識符特性(identifier features):

 

• The name of an operator feature as it appears in the feature’s declaration is of the form infix "§" or prefix "§", rather than an identifier.

·當出現在特性聲明中的時候,一個運算符特性的名字是infix "§"或是prefix "§"的形式,而不是一個標識符。

 

• Calls to operator features are of the form u § v (in the infix case) or § u (in the prefix case) rather than using dot notation.

·調用運算符特性是u § v(中綴)或§ u(前綴)的形式,而不是使用圓點符號。

 

As a consequence of the second property, operator features only support qualified calls. If a routine of class REAL contained, in the first version given earlier, an unqualified call of the form plus (y), yielding the sum of the current number and y, the corresponding call will have to be written Current + y in the second version. With an identifier feature, the corresponding notation, Current.plus (y), is possible but we would not normally use it in practice since it is uselessly wordy. With an operator feature we do not have a choice.

第二個屬性的結果是,運算符特性只支持限定調用。在之前給出的第一個版本中,如果類REAL的一個例程包含有一個plus (y)形式的非限定調用,其產生當前數字與y的和,那麼在第二個版本中相應的調用將必須寫成Current + y。帶有一個標識符的相應符號是Current.plus (y),這沒什麼問題但是由於拖沓冗長我們通常在實際上並不使用。對於一個運算符特性我們沒有選擇。

 

Other than the two syntactical differences noted, operator features are fully equivalent to identifier features; for example they are inherited in the same way. Any class, not just the basic classes such as REAL, can use operator features; for example, it may be convenient in a class VECTOR to have a vector addition function called infix "+".

除了這兩個語法的不同之外,運算符特性完全等同於標識符特性;比如可以用同樣的方式繼承它們。不僅僅是象REAL這樣的基本類,任何的類都能夠使用運算符特性;譬如,在類VECTOR中,有一個infix "+"向量加法函數是很方便的。

 

The following rule will apply to the operators used in operator features. An operator is a sequence of one or more printable characters, containing no space or newline, and beginning with one of

+ – S / < > = / ^ @ # | &

隨後的規則將應用到在運算符特性中使用的運算符上。一個運算符是一個或多個可打印字符的序列,不包含空格和換行,並以下列的其中一個開頭+ – S / < > = / ^ @ # | &

 

In addition, the following keywords, used for compatibility with usual Boolean notation, are permitted as operators:

另外,下面和通常的布爾符號兼容的關鍵字,被認爲是運算符:

not and or xor and then or else implies

 

In the non-keyword case, the reason for restricting the first character is to preserve the clarity of software texts by ensuring that any use of an infix or prefix operator is immediately recognizable as such from its first character.

在非關鍵字的情況中,限定第一個字符的原因是保護軟件代碼的清晰度,這確保任何使用中綴或前綴的運算符可以立刻從其第一個字符中辨認出來。   

 

Basic classes (INTEGER etc.) use the following, known as standard operators:

• Prefix: + – not.

• Infix: + – S / < > <= >= // // ^ and or xor and then or else implies.

基本類(INTEGER等)使用下列的標準運算符:

·前綴:+ – not

·中綴:+ – S / < > <= >= // // ^ and or xor and then or else implies

 

The semantics is the usual one. // is used for integer division, // for integer remainder, ^ as the power operation, xor as exclusive or. In class BOOLEAN, and then and or else are variants of and and or, the difference being explained in a later chapter, and implies is the implication operator, such that a implies b is the same as (not a) or else b.

語義也符合慣例。//用作整數的除,//用作整數的餘數,^是冪運算,xor是異或。在類BOOLEAN中,and thenor elseandor的變體,不同之處將在後面解釋,implies蘊涵運算符,a implies b(not a) or else b一樣。

[]: implies有的書也稱爲蘊涵算子.

 

Operators not in the “standard” list are called free operators. Here are two examples of possible operator features using free operators:

不在“標準”列表中的運算符叫做自由運算符(free operators)。這裏有兩個使用自由運算符的例子:

 

• When we later introduce an ARRAY class, we will use the operator feature infix "@" for the function that returns an array element given by its index, so that the i-th element of an array a may be written simply as a @ i.

·當我們後面介紹ARRAY類的時候,對於返回一個給定索引的數組元素的函數,我們將使用運算符特性infix "@",因此,一個數組a的第i個元素可以簡單地寫成a @ i

 

• In class POINT, we could have used the name infix "|–|" instead of distance, so that the distance between p1 and p2 is written p1 |–| p2 instead of p1.p2.

·在類POINT中,我們能夠使用infix "|–|"命名來替代distance,因此,p1p2之間的距離用p1 |–| p2來替代p1.distance (p2)

 

The precedence of all operators is fixed; standard operators have their usual precedence, and all free operators bind tighter than standard operators.

所有運算符的優先級是固定的;標準運算符有着它們通常的優先級,所有的自由運算符比標準運算符綁定得更加緊密。

 

The use of operator features is a convenient way to maintain compatibility with well-accepted expression notation while ensuring the goal of a fully uniform type system (as stated by the Object Rule) and of a single fundamental mechanism for computation. In the same way that treating INTEGER and other basic types as classes does not need to cause any performance problem, treating arithmetic and boolean operations as features does not need to affect efficiency. Conceptually, a + x is a feature call; but any good compiler will know about the basic types and their features, and will be able to handle such a call so as to generate code at least as good as the code generated for a + x in C, Pascal, Ada or any other language in which + is a special hard-wired language construct.

當需要確保一個完整統一的類型系統(如對象規則的陳述)和一個單一基本的計算機制的目標的時候,使用運算符特性是一種方便的方法,以公認的表達式符號維護着兼容性。用同樣的方法把INTEGER和其它的基本類型視爲類,這不會引發任何的性能問題,把算術和布爾運算視爲特性不會影響效率。從概念上來說,a + x是一個特性調用;但是任何優秀的編譯器都知道基本類型和它們的特性,同時能夠處理這樣的一種調用,以致生成的代碼至少和在CPasclAda和任何其它的把+當作一個特別固化的語言結構的語言爲a + x生成的代碼一樣好。

 

When using operators such as +, < and others in expressions, we may forget, most of the time, that they actually stand for feature calls; the effect of these operators is the one we would expect in traditional approaches. But it is pleasant to know that, thanks to the theoretical context of their definition, they do not cause any departure from object-oriented principles, and fit in perfectly with the rest of the method.

當在表達式中使用諸如+<等等運算符的時候,我們幾乎可以忘記它們其實是特性調用;這些運算符的效果是和我們在傳統的方法中所期待的一樣。但是,很高興地知道的是,由於理論上的定義環境,它們並沒有引起任何背離面向對象原則的事情,而且極好的符合了其它的方式。

 

7.8 SELECTIVE EXPORTS AND INFORMATION HIDING

7.8 選擇性輸出和信息隱藏

 

In the examples seen so far all the features of a class were exported to all possible clients. This is of course not always acceptable; we know from earlier discussion how important information hiding is to the design of coherent and flexible architectures.

到目前爲止在所舉的例子中,類的所有特性都對所有可能的客戶輸出了。當然這不總是可以接受的們從早先的討論中懂得了如何隱藏重要信息是連貫的和靈活的系統架構的設計。

 

Let us take a look at how we can indeed restrict features to no clients, or to some clients only. This section only introduces the notation; the chapter on the design of class interfaces will discuss its proper use.

讓我們看看如何真正地限制特性,不對客戶開放,或者只對某些客戶開放。 這個部分只介紹符號;類接口設計的章節中將討論其正確的用法。

 

Full disclosure

完全公開

 

By default, as noted, features declared without any particular precaution are available to all clients. In a class of the form

class S1 feature

f ¼

g ¼

¼

end

features f, g, ¼ are available to all clients of S1. This means that in a class C, for an entity x declared of type S1, a call

x.f ¼

is valid, provided the call satisfies the other validity conditions on calls to f, regarding the number and types of arguments if any. (For simplicity the discussion will use identifier features as examples, but it applies in exactly the same way to operator features, for which the clients will use calls in infix or prefix form rather than dot notation.)

缺省的情況下,沒有任何特別保護的特性聲明是對所有的客戶都有效的。在類

class S1 feature

f ¼

g ¼

¼

end

的形式中,特性fgS1的所有客戶都可用。這意味着在類C中,對於一個聲明爲類型S1的實體x,調用x.f ¼是有效的,提供調用滿足其它有效性達到調用的條件,如果有的話,關於參數的數目和類型。(爲了簡單,討論將使用標識符特性作爲例子,但是它完全可以對運算符適用同樣的方式,客戶將以中綴或前綴而不是圓點符號來使用調用。)

 

Restricting client access

限制客戶訪問

 

To restrict the set of clients that can call a certain feature h, we will use the possibility for a class to have two or more feature clauses. The class will then be of the form

要限制那些能夠調用一個特定特性h的客戶,我們將對一個類使用兩個或是更多個feature子句。那麼類將呈現出這個形式

class S2 feature

f ¼

g ¼

feature {A, B}

h ¼

¼

End

 

Features f and g have the same status as before: available to all clients. Feature h is available only to A and B, and to their descendants (the classes that inherit directly or indirectly from A or B). This means that with x declared of type S2 a call of the form

x.h ¼

is invalid unless it appears in the text of A, B, or one of their descendants.

特性fg有着和以往一樣的狀態:對所有的客戶開放。特性h只是對AB有效,也對它們的後代(從AB直接或間接繼承的類)有效。這意味着x聲明成S2類型,x.h ¼形式的調用是無效的,除非它出現在AB或是後代的代碼中。

 

As a special case, if you want to hide a feature i from all clients, you may declare it as exported to an empty list of clients:

作爲一個特殊的情況,如果您想對所有的客戶隱藏特性i,您可以把它聲明成導出一個空的客戶列表:

class S3 feature { }

i ¼

end

 

In this case a call of the form x.i (¼) is always invalid. The only permitted calls to i are unqualified calls of the form

i (¼)

appearing in the text of a routine of S3 itself, or one of its descendants. This mechanism ensures full information hiding.

在這種情況下,x.i (¼)形式的調用總是無效的。唯一被允許的i調用是非限定調用形式i (¼),這出現在S3自身的例程代碼中,或是其後代中。這種機制確保了完全的信息隱藏。

 

The possibility of hiding a feature from all clients, as illustrated by i, is present in many O-O languages. But most do not offer the selective mechanism illustrated by h: exporting a feature to certain designated clients and their proper descendants. This is regrettable since many applications will need this degree of fine control.

正如i所描述的那樣,對所有的客戶隱藏一個特性的可能性出現在許多OO語言中。但是其中大部分並不提供h所表現出的那種選擇性機制:導出一個特性給某個指定的客戶和它們擁有的後代。由於許多的應用需要這種細微控制的程度,所以有些遺憾。

 

The discussion section of the present chapter explains why selective exports are a critical part of the architectural mechanisms of the object-oriented approach, avoiding the need for “super-modules” that would hamper the simplicity of the method.

本章的討論解釋了爲什麼選擇性的導出是面向對象方法的架構機制中一個至關重要的部分,這避免了對破壞方法簡單性的“超級模塊”的需要。

 

We will encounter various examples of selective exports in subsequent chapters, and will study their methodological role in the design of good modular interfaces.

我們將後面的章節中遇到各種選擇性導出的例子,並會瞭解到它們在良好模塊接口設計中所對應的方法角色。

 

Style for declaring secret features

聲明祕密特性的式樣

 

A small point of style. A feature declared in the form used above for i is secret, but perhaps this property does not stand out strongly enough from the syntax. In particular, the difference with a public feature may not be visible enough, as in

式樣上的一個小小的要點。在上面i使用的形式中有一個特性聲明是祕密的,但是也許這個屬性沒有足夠地從語法中突出出來。尤其,與公共特性的不同之處並沒有充分地表現出來:

class S4 feature

exported¼

feature { }

secret ¼

end

where feature exported is available to all clients whereas secret is available to no client. The difference between feature { }, with an empty list in braces, and feature, with no braces, is a little weak. For that reason, the recommended notation uses not an empty list but a list consisting of the single class NONE, as in

其中,特性exported是對所有的客戶有效,而secret不對客戶開放。空大括號的feature { }和不帶大括號的feature,它們之間的不同並不明顯。基於這個原因,所介紹的符號不使用一個空的列表,而是一個包含一個單一類NONE的列表:

class S5 feature

¼ Exported ¼

feature {NONE}

¼ Secret ¼

End

 

Class NONE, which will be studied in a later chapter in connection with inheritance, is a Base library class which is so defined as to have no instances and no descendants. So exporting a feature to NONE only is, for all practical purposes, the same as keeping it secret. As a result there is no meaningful difference between the forms illustrated by S4 and S5; for reasons of clarity and readability, however, the second form is preferred, and will be employed in the rest of this book whenever we need to introduce a secret feature.

NONE將在後面連同繼承一起學習。它是一個基礎庫類,沒有實例也沒有後代。因此,實際上只導出一個特性給NONE是和保持其祕密性一樣的。結果在S4S5所描繪的形式之間並沒有什麼意義上的不同;然而,因爲清晰度和可讀性的原因,第二種形式更好,只要在本書中我們需要使用一個祕密特性的時候我們都將採用這種形式。

 

Exporting to yourself

導出給自己

 

A consequence of the rules seen so far is that a class may have to export a secret feature.

Assume the declaration

到目前爲止,規則的結論是一個類可以導出一個祕密特性。假設聲明如下

indexing

note: "Invalid as it stands (see explanations below)"

class S6 feature

x: S6

my_routine is do ¼ print (x.secret) ¼ end

feature {NONE}

secret: INTEGER

end -- class S6

 

By declaring x of type S6 and making the call x.secret, the class becomes its own client. But this call is invalid, since secret is exported to no class! That the unauthorized client is S6 itself does not make any difference: the {NONE} export status of secret makes any call x.secret invalid. Permitting exceptions would damage the simplicity of the rule.

聲明類型爲S6x並調用x.secret,類變成了它自己本身的客戶。但是由於secret並不對任何類導出,所以這個調用是無效的!非授權的客戶是S6本身並不能使之有所不同:secret{NONE}導出狀態使得任何的x.secret調用都無效。允許特例將破壞規則的簡單性。

 

The solution is simple: instead of feature {NONE} the header of the second feature clause should read feature {S6}, exporting the feature to the class itself and its descendants.

解決方案很簡單:第二feature子句的頭信息用feature {S6}來取代feature {NONE}它輸出特性到類的本身和後代中。

 

Be sure to note that this is only needed if you want to use the feature in a qualified call such as appears in print (x.secret). If you are simply using secret by itself, as in the instruction print (secret), you of course do not need to export it at all. Features declared in a class must be usable by the routines of the class and its descendants; otherwise we could never do anything with a secret feature! Only if you use the feature indirectly in a qualified call do you need to export it to yourself.

要注意的是,這只有在您想使用限定性調用的特性,如print (x.secret)顯示的那樣時才需要。如果您只是簡單地使用secret本身,如指令print (secret),您當然根本不需要導出。在類中聲明的特性必須能被類和後代的例程所使用;否則,我們根本不能處理祕密特性!只有您在限定性調用中間接地使用一個特性,您才需要導出到類本身中去。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章