面向對象軟件構造(第2版)-第3章 模塊性Modularity

From the goals of extendibility and reusability, two of the principal quality factors introduced in chapter 1, follows the need for flexible system architectures, made of autonomous software components. This is why chapter 1 also introduced the term modularity to cover the combination of these two quality factors.

擴充性和複用性這兩個主要的品質因數在第1章介紹過了,從其目標來看,它們遵循了靈活的系統架構的需求,並由獨立的軟件組件組成.這也是第1章會介紹術語塊性包括這二個品質因數組合的原因.

 

Modular programming was once taken to mean the construction of programs as assemblies of small pieces, usually subroutines. But such a technique cannot bring real extendibility and reusability benefits unless we have a better way of guaranteeing that the resulting pieces — the modules — are self-contained and organized in stable architectures. Any comprehensive definition of modularity must ensure these properties.

一旦模塊編程被採用,就意味着程序的構造如同散件組裝,這些散件通常是些子程序.但是這樣的技術不能夠帶來真正的擴充性和複用性的利益,除非我們有更好的方法來保證最終的散件模塊(module)在穩定的架構中是獨立的和組織化的.任何完整的模快性定義都必須確保這些屬性.

 

A software construction method is modular, then, if it helps designers produce software systems made of autonomous elements connected by a coherent, simple structure. The purpose of this chapter is to refine this informal definition by exploring what precise properties such a method must possess to deserve the “modular” label. The focus will be on design methods, but the ideas also apply to earlier stages of system construction (analysis, specification) and must of course be maintained at the implementation and maintenance stages.

那麼,如果一個系統是由獨立的元素以連貫簡單的結構所連接而成,一個軟件構造方法幫助設計者產生了這樣的軟件系統,那麼這個方法就是模塊化的.通過研究把一個方法進行模塊化的一些精確屬性,來改善這個非正式的定義,這是本章的目的.焦點會集中在設計方式上,但是其思想也適用於系統構造(分析,規格)的早期階段,當然也必須在實現和維護階段繼續實現.

 

As it turns out, a single definition of modularity would be insufficient; as with software quality, we must look at modularity from more than one viewpoint. This chapter introduces a set of complementary properties: five criteria, five rules and five principles of modularity which, taken collectively, cover the most important requirements on a modular design method.

事實上,一個單一的性的定義是不夠的;同時由於軟件品質,我們必須從多方面來了解. 這章介紹一組補充的屬性: 性的五條標準(criteria),五件規則(rules)和五項原則(principles), 全部的這些涵蓋了一個模塊設計方式上的最重要的要求.

 

For the practicing software developer, the principles and the rules are just as important as the criteria. The difference is simply one of causality: the criteria are mutually independent — and it is indeed possible for a method to satisfy one of them while violating some of the others — whereas the rules follow from the criteria and the principles follow from the rules.

對於一個專業的軟件開發者,原則和規則是同標準一樣的重要.不同之處僅是一個因果關係: 標準是互相獨立的 對於一個方法而言,確實可能滿足了其中的一個卻違犯了其它的標準 然而規則從標準中得出,原則從規則中而來.

 

You might expect this chapter to begin with a precise description of what a module looks like. This is not the case, and for a good reason: our goal for the exploration of modularity issues, in this chapter and the next two, is precisely to analyze the properties which a satisfactory module structure must satisfy; so the form of modules will be a conclusion of the discussion, not a premise. Until we reach that conclusion the word “module” will denote the basic unit of decomposition of our systems, whatever it actually is. If you are familiar with non-object-oriented methods you will probably think of the subroutines present in most programming and design languages, or perhaps of packages as present in Ada and (under a different name) in Modula. The discussion will lead in a later chapter to the O-O form of module — the class — which supersedes these ideas. If you have encountered classes and O-O techniques before, you should still read this chapter to understand the requirements that classes address, a prerequisite if you want to use them well.

您可能會認爲,本章應該從模塊特徵之精確描述開始.但卻不是這樣的,並且有一個很好的理由:在這章和下兩章中,爲了探求性的議題,我們的目標是要精確地分析一個符合要求的模塊結構所必須滿足的屬性;因此模塊的形式將會是討論的結論而不是前提.在我們得出結論之前,模塊這個字將一直表示系統中可分解的基本單元,而無論實際上是什麼.如果您熟悉非面向對象的方法,您可能會想到在大多數的程序和設計語言中的子程序的表現形式,如同是在Ada和(在不同的名字之下)Modula中所呈現的那樣.在下面的章節中,討論將會引導出模塊的OO形式來代替這些想法.如果您以前遇到過類和OO技術,您應該仍然閱讀本章來了解類的作用,如果您想更好的使用它們,這是必須要看的.

 

 

3.1 FIVE CRITERIA

3.1 標準

 

A design method worthy of being called “modular” should satisfy five fundamental requirements, explored in the next few sections:

被稱爲模塊的設計方式應該滿足五條基本的條件,我們將在下面的部分中一一的討論:

 

• Decomposability. 分解性

• Composability. 組合性

• Understandability. 理解性

• Continuity. 連續性

• Protection. 保護性

 

Modular decomposability

A software construction method satisfies Modular Decomposability if it helps in the task of decomposing a software problem into a small number of less complex subproblems, connected by a simple structure, and independent enough to allow further work to proceed separately on each of them

如果一個軟件構造方法能把一個軟件問題分解成很多較簡單的子問題,並把這些子問題用一個簡單的架構連接起來,而且能夠完全獨立的在每一個子問題上再更進一步的分解,那麼,這個方法就滿足模塊的分解性.

 

 

 


模塊分解性

 

The process will often be self-repeating since each subproblem may still be complex enough to require further decomposition.

由於每個子問題可能仍然十分複雜,需要進一步的分解,這個過程就將不斷的循環往復.

 

 


A corollary of the decomposability requirement is division of labor: once you have decomposed a system into subsystems you should be able to distribute work on these subsystems among different people or groups. This is a difficult goal since it limits the dependencies that may exist between the subsystems:

分解性需求的必然結果是人工的分配: 一旦您已經把一個系統分解成子系統,您應該能夠把這些子系統的工作分配給不同的人或組.由於在各個子系統之間存在的關聯的限制,這會是一個困難的目標:

 

• You must keep such dependencies to the bare minimum; otherwise the development of each subsystem would be limited by the pace of the work on the other subsystems.

您必須把這樣的關聯儘可能的減小到最少;否則每個子系統的開發會受制於其它子系統的工作進度.

 

• The dependencies must be known: if you fail to list all the relations between subsystems, you may at the end of the project get a set of software elements that appear to work individually but cannot be put together to produce a complete system satisfying the overall requirements of the original problem.

必須要瞭解關聯: 如果您不能列出子系統之間的所有關係,您可以在項目結束的時候得到一系列的軟件元素,這些組件看上去能獨立工作,但是卻不能夠被整合成一個完整的系統來滿足最初問題的全部需求.

 

The most obvious example of a method meant to satisfy the decomposability criterion is top-down design. This method directs designers to start with a most abstract description of the system’s function, and then to refine this view through successive steps, decomposing each subsystem at each step into a small number of simpler subsystems, until all the remaining elements are of a sufficiently low level of abstraction to allow direct implementation. The process may be modeled as a tree.

符合分解性標準的方法中最明顯的例子是由上而下設計(top-down design).這種方法指導設計者由系統函數的一個最抽象描述開始,然後經過連續的步驟精煉這個描述,在每個步驟中把每個子系統分解成幾個更簡單的子系統,直到所有的元素抽象化程度都足夠低可以直接實現.這個過程可以模擬成樹狀.

 

 


A typical counter-example is any method encouraging you to include, in each software system that you produce, a global initialization module. Many modules in a system will need some kind of initialization — actions such as the opening of certain files or the initialization of certain variables, which the module must execute before it performs its first directly useful tasks. It may seem a good idea to concentrate all such actions, for all modules of the system, in a module that initializes everything for everybody. Such a module will exhibit good “temporal cohesion” in that all its actions are executed at the same stage of the system’s execution. But to obtain this temporal cohesion the method would endanger the autonomy of modules: you will have to grant the initialization module authorization to access many separate data structures, belonging to the various modules of the system and requiring specific initialization actions. This means that the author of the initialization module will constantly have to peek into the internal data structures of the other modules, and interact with their authors. This is incompatible with the decomposability criterion.

一個典型的反例是,在您創造的每個軟件系統中,所有的方法都鼓勵您包括一個全局的初始化模塊.一個系統中的許多模塊需要多種多樣的初始化如打開某個文件或初始化某些變量之類的行爲,在運行第一個直接有效的任務之前,模塊必須要運行這些初始化.把所有的初始化行爲都集中起來,在一個模塊中爲系統的所有部分做初始化,這看上去是個不錯的主意.所有的這些動作都在系統執行的相同階段執行,這樣的模塊將會展示良好的時間性內聚(temporal cohesion).但是爲了獲得這種時間性內聚,這種方法會危及模塊的自治:您將不得不授權初始化模塊訪問許多獨立的數據結構,這些數據結構屬於系統的各種不同的模塊而且需要特定的初始化行爲.這意謂初始化模塊的作者將會經常地看到其它模塊的內部數據結構,而且和它們的作者交互.這與分解性標準不相容.

 

In the object-oriented method, every module will be responsible for the initialization of its own data structures.

在面向對象的方法中,每個模塊將會負責它自己數據結構的初始化.

 

Modular composability

模塊組合性

A method satisfies Modular Composability if it favors the production of software elements which may then be freely combined with each other to produce new systems, possibly in an environment quite different from the one in which they were initially developed.

一些軟件元素在不同於它們最初被開發的環境中,彼此之間可以自由組合以產生新的系統,如果一個方法支持這種編寫方式,那麼這種方法滿足模塊的組合性.

 

 

 


 

Where decomposability was concerned with the derivation of subsystems from overall systems, composability addresses the reverse process: extracting existing software elements from the context for which they were originally designed, so as to use them again in different contexts.

這裏,分解性關注於把整個系統分解成子系統,而組合性從事相反的過程:從原始設計的環境中提取出現存的軟件元素,使得在不同的環境中再一次使用它們.

 


 

A modular design method should facilitate this process by yielding software elements that will be sufficiently autonomous — sufficiently independent from the immediate goal that led to their existence — as to make the extraction possible.

一個模塊的設計方法應該通過產生完全獨立的軟件元素促進這樣的過程從導致它們存在的直接目標中充份地獨立直到能夠使它們提取出來.

 

Composability is directly connected with the goal of reusability: the aim is to find ways to design software elements performing well-defined tasks and usable in widely different contexts. This criterion reflects an old dream: transforming the software design process into a construction box activity, so that we would build programs by combining standard prefabricated elements.

組合性直接地與複用性的目標相關聯:目標是要找到方法設計軟件元素,來完成明確定義的任務和在廣泛不同的環境中使用.這一個標準反映了一箇舊夢:把軟件設計過程轉換成一個建築箱體預製板的行爲,這樣我們就能組合標準預製元素來建造程序.

 

Example 1: subprogram libraries. Subprogram libraries are designed as sets of composable elements. One of the areas where they have been successful is numerical computation, which commonly relies on carefully designed subroutine libraries to solve problems of linear algebra, finite elements, differential equations etc.

1:子程序庫,子程序庫被設計成一組可組合的元素.一個成功的領域是數值計算,這通常建立在那些仔細設計的子程序庫之上,這些庫用來解決線性代數,有限元,微分方程等等之類的問題.

 

Example 2: Unix Shell conventions. Basic Unix commands operate on an input viewed as a sequential character stream, and produce an output with the same standard structure. This makes them potentially composable through the | operator of the command language (“shell”): A | B represents a program which will take A’s input, have A process it, send the output to B as input, and have it processed by B. This systematic convention favors the composability of software tools.

2: Unix命令行定義.基本的Unix指令把輸入操作看成一個連續的字符流,而且用同樣的標準結構產生一個輸出.這使它們通過命令語言(“shell”)中的操作符| 來潛在的組合起來: A | B表示一個程序輸入A,並輸出B.這個系統的定義證實了軟件工具的組合性.

 

Counter-example: preprocessors. A popular way to extend the facilities of programming languages, and sometimes to correct some of their deficiencies, is to use “preprocessors” that accept an extended syntax as input and map it into the standard form of the language. Typical preprocessors for Fortran and C support graphical primitives, extended control structures or database operations. Usually, however, such extensions are not compatible; then you cannot combine two of the preprocessors, leading to such dilemmas as whether to use graphics or databases.

反例: 預處理程序.爲了擴充程序語言的工具,有時改正一些它們的不足,一個流行的方法是使用"預處理程序",來接受一個擴充的語法作爲輸入,並把它映射進語言的標準形式之內.典型的FORTRAN和C的預處理程序支持基本的圖形,延伸結構控制或數據庫操作. 然而,通常這樣的擴充並不相容;結果您不能夠連接二個預處理程序,這導致了是使用圖形還是數據庫諸如此類的困境.

 

Composability is independent of decomposability. In fact, these criteria are often at odds. Top-down design, for example, which we saw as a technique favoring decomposability, tends to produce modules that are not easy to combine with modules coming from other sources. This is because the method suggests developing each module to fulfill a specific requirement, corresponding to a subproblem obtained at some point in the refinement process. Such modules tend to be closely linked to the immediate context that led to their development, and unfit for adaptation to other contexts. The method provides neither hints towards making modules more general than immediately required, nor any incentives to do so; it helps neither avoid nor even just detect commonalities or redundancies between modules obtained in different parts of the hierarchy.

組合性分解性無關.事實上,這些標準時常不一致.舉例來說,我們把由上而下的設計看作是一個支持分解性的技術,它試圖產生的模塊並不能輕易地連接來自其它源代碼的模塊.這是因爲該方法建議開發各自的模塊實現特定的需求,符合在細化的過程中某些點上產生的子問題.這樣的模塊趨向於接近它們所開發的直接的上下文環境,並不能改編以適應其它的環境.此方法既沒有提供使模塊比直接需求更泛化的線索,也不能提供這麼做的動機;它既不能幫助避免甚至不能發現在不同層次中所需模塊之間的共性或冗餘.

 

That composability and decomposability are both part of the requirements for a modular method reflects the inevitable mix of top-down and bottom-up reasoning — a complementarity that René Descartes had already noted almost four centuries ago, as shown by the contrasting two paragraphs of the Discourse extract at the beginning of part B.

對於一個反映了由上而下和由下而上的推論的必然混合的模塊化方法,組合性分解性兩者皆是需求的部份B部份開頭,兩幅從Discourse截取的差別明顯的圖形,顯示了René Descartes幾乎在四個世紀以前就已經提出了一個補充.

 

Modular understandability

模塊理解性

A method favors Modular Understandability if it helps produce software in which a human reader can understand each module without having to know the others, or, at worst, by having to examine only a few of the others.

如果用某個方法幫助編寫軟件,讀者能在不瞭解其它模塊的情況下理解每個模塊,或者,最壞也只須瞭解少數其它的模塊.那麼,這個方法支持模塊的理解性.

 

 

 


 

The importance of this criterion follows from its influence on the maintenance process. Most maintenance activities, whether of the noble or not-so-noble category, involve having to dig into existing software elements. A method can hardly be called modular if a reader of the software is unable to understand its elements separately.

這個標準的重要性是影響隨後的維護過程.大多數的維護行爲,不管是重要的或是不重要的,都不得不深入理解已存在的軟件元素.如果軟件讀者(維護人員)不能夠獨立的理解這些元素,那麼這個方法很難被稱之爲模塊化的.

 

 

 

 


This criterion, like the others, applies to the modules of a system description at any level: analysis, design, implementation.

其它的一樣,這個標準適用於任何層次的系統描述模塊:分析,設計,實現.

 

Counter-example: sequential dependencies. Assume some modules have been so designed that they will only function correctly if activated in a certain prescribed order; for example, B can only work properly if you execute it after A and before C, perhaps because they are meant for use in “piped” form as in the Unix notation encountered earlier:

A | B | C

Then it is probably hard to understand B without understanding A and C too.

反例: 連續的關聯. 假設一些模塊由於設計的原因,以至於它們只能在特定的命令順序下才正確地動作;舉例來說,如果您在A之後C之前運行B,它才能正確地工作,也許因爲這就是在先前遇到的Unix符號中管道(piped)的使用形式:

A | B | C

那麼,不瞭解AC的情況下,也不可能理解B.

 

In later chapters, the modular understandability criterion will help us address two important questions: how to document reusable components; and how to index reusable components so that software developers can retrieve them conveniently through queries. The criterion suggests that information about a component, useful for documentation or for retrieval, should whenever possible appear in the text of the component itself; tools for documentation, indexing or retrieval can then process the component to extract the needed pieces of information. Having the information included in each component is preferable to storing it elsewhere, for example in a database of information about components.

在稍後的章節中,模塊的理解性標準將幫助我們處理二個重要的問題:如何編寫可複用組件的文檔;如何索引可複用組件以便軟件開發者能夠通過查詢方便地得到它們.這個標準建議,對於文檔或檢索都有用的組件信息,應該儘可能的出現在組件本身的文本中;文檔,索引或檢索的工具能各取所需的信息.有些包含在各自組件中的信息儲存在別處可能更好,如在數據庫中about組件.

 

Modular continuity

模塊連續性

A method satisfies Modular Continuity if, in the software architectures that it yields, a small change in a problem specification will trigger a change of just one module, or a small number of modules.

在使用某個方法產生的軟件結構中,如果在一個問題規格方面的微小改變將只會引起一個模塊的變化,或少量模塊的變化.那麼,這個方法滿足模塊的連續性.

 

 

 


 

This criterion is directly connected to the general goal of extendibility. As emphasized in an earlier chapter, change is an integral part of the software construction process. The requirements will almost inevitably change as the project progresses. Continuity means that small changes should affect individual modules in the structure of the system, rather than the structure itself.

這個標準直接地關聯了擴充性的大致目標.如先前的章節所強調,變化是軟件構造過程的主要部份.在項目開發的過程中這樣變化是不可避免的.連續性意味着微小的變化應該影響系統結構中的個別的模塊,而並非結構本身.

 

The term “continuity” is drawn from an analogy with the notion of a continuous function in mathematical analysis. A mathematical function is continuous if (informally) a small change in the argument will yield a proportionally small change in the result. Here the function considered is the software construction method, which you can view as a mechanism for obtaining systems from specifications:

術語連續性是從數學分析裏的連續函數觀念的類推中描繪出來的.如果(非正式地)參數的微小改變會引起結果中的等比例地變化,那麼這個數學函數就是連續的.這裏所考慮的函數是軟件構造方法,您能觀察到從規格中獲取系統的機制:

 

software_construction_method: Specification ® System

 


This mathematical term only provides an analogy, since we lack formal notions of size for software. More precisely, it would be possible to define a generally acceptable measure of what constitutes a “small” or “large” change to a program; but doing the same for the specifications is more of a challenge. If we make no pretense of full rigor, however, the concepts should be intuitively clear and correspond to an essential requirement on any modular method.

由於我們缺乏軟件尺寸大小的觀念,因此這個數學術語只是提供一個類推的結果.更精確的,對於程序的一個小的大的變化程度,它只是儘可能地定義一個一般的可接受的衡量標準;但是對規格來說做相同的事卻有更多的挑戰.然而,如果我們並沒有要求那麼嚴格的話,這個概念應該是直觀清晰的並且符合在任何的模塊方法上的實質需求.

 

Example 1: symbolic constants. A sound style rule bars the instructions of a program from using any numerical or textual constant directly; instead, they rely on symbolic names, and the actual values only appear in a constant definition (constant in Pascal or Ada, preprocessor macros in C, PARAMETER in Fortran 77, constant attributes in the notation of this book). If the value changes, the only thing to update is the constant definition. This small but important rule is a wise precaution for continuity since constants, in spite of their name, are remarkably prone to change.

1: 符號常數. 一條合理的規則禁止把任何數字或本文常數直接地使用在程序的指令中;而是依賴於符號名,並且真實的數值只在一個常數定義中出現(PascalAda常數(constant),C的預處理程序宏, Fortran 77叄數(PARAMETER),在本書符號中的常數屬性).如果數值變化,唯一要做的是更新其常數定義.儘管它們的名字(是常數),但常數都有顯著地改變傾向,所以這條小的但重要的規則對於連續性是一種明智地預防.

 

Example 2: the Uniform Access principle. Another rule states that a single notation should be available to obtain the features of an object, whether they are represented as data fields or computed on demand. This property is sufficiently important to warrant a separate discussion later in this chapter.

2:統一存取原則. 另外的一條規則規定了一個單一符號應該能有效地獲得對象的特性,不管是否它們被表現爲數據字段或請求計算上.這個屬性對於保證本章中稍後的另一個討論非常重要.

 

Counter-example 1: using physical representations. A method in which program designs are patterned after the physical implementation of data will yield designs that are very sensitive to slight changes in the environment.

反例1:使用實際表示法.一個方法,在其中程序設計會在數據實際實現之後被模式化,這將會產生對環境方面輕微的改變都非常敏感的設計.

 

Counter-example 2: static arrays. Languages such as Fortran or standard Pascal, which do not allow the declaration of arrays whose bounds will only be known at run time, make program evolution much harder.

反例2: 靜態數組.Fortran或標準Pascal這樣的語言,不允許只能在運行的時候才知道綁定的數組聲明,這將使程序發展更加困難.

 

Modular protection

模塊保護性

A method satisfies Modular Protection if it yields architectures in which the effect of an abnormal condition occurring at run time in a module will remain confined to that module, or at worst will only propagate to a few neighboring modules.

如果一個方法產生的結構,在其中一個運行的模塊裏發生的反常狀態將保持限制在當前的模塊中,或最壞也只將會影響到少數附近的模塊,那麼,這個方法滿足模塊的保護性.

 

 

 


 

The underlying issue, that of failures and errors, is central to software engineering. The errors considered here are run-time errors, resulting from hardware failures, erroneous input or exhaustion of needed resources (for example memory storage). The criterion does not address the avoidance or correction of errors, but the aspect that is directly relevant to modularity: their propagation.

在下面的議題中,失敗和錯誤對軟件工程來說都是重要的.在這裏所考慮的錯誤是運行時錯誤,起因於硬件的失敗,錯誤的輸入或所需資源(例如內存儲存)的耗盡.這個標準並沒有專注於錯誤的避免或校正,但是卻提出了直接與模塊化有關的方面:它們的傳播.

 

 

 


Example: validating input at the source. A method requiring that you make every module that inputs data also responsible for checking their validity is good for modular protection.

: 源輸入的確認.一個方法要求您對可以輸入數據的每個模塊也要有責任檢查數據的有效性,這有益於模塊的保護.

 

Counter-example: undisciplined exceptions. Languages such as PL/I, CLU, Ada, C++ and Java support the notion of exception. An exception is a special signal that may be “raised” by a certain instruction and “handled” in another, possibly remote part of the system. When the exception is raised, control is transferred to the handler. (Details of the mechanism vary between languages; Ada or CLU are more disciplined in this respect than PL/I.) Such facilities make it possible to decouple the algorithms for normal cases from the processing of erroneous cases. But they must be used carefully to avoid hindering modular protection. The chapter on exceptions will investigate how to design a disciplined exception mechanism satisfying the criterion.

反例:不健全的異常.像是PL/I, CLU, Ada, C++ Java這樣的語言支持異常的觀念.異常是一個特別的信號,可以被特定的指令拋出,並且在別處,有可能是系統的遠程部份被處理.當異常被拋出的時候,控制被轉移到處理程序.(在語言之間此機制的細節有所不同;AdaCLU在這方面比PL/I.更科學.) 這樣的方法儘可能的在錯誤情況處理中減輕對正常情況下算法的影響.但是必須小心地使用它們,避免妨礙模塊的保護性.在介紹異常的章節中將會研究該如何設計一個健全的異常機制來滿足此標準.

 

 

3.2 FIVE RULES

3.2 五規則

 

From the preceding criteria, five rules follow which we must observe to ensure modularity:

在上述標準之後的是五件規則,我們必須遵守它以確保.

 

• Direct Mapping. 直接映射          

• Few Interfaces. 少量接口

• Small interfaces (weak coupling). 小型接口(弱耦合)

• Explicit Interfaces. 精確接口

• Information Hiding. 信息隱藏

 

The first rule addresses the connection between a software system and the external systems with which it is connected; the next four all address a common issue — how modules will communicate. Obtaining good modular architectures requires that communication occur in a controlled and disciplined way.

第一件規則描述了一個軟件系統和外部系統之間的連結關係; 餘下的全部四件描述了一個普通的議題模塊之間如何溝通.獲得一個良好的模塊架構需要一個易控制而且健全的通訊方式.

 

Direct Mapping

直接映射

 

Any software system attempts to address the needs of some problem domain. If you have a good model for describing that domain, you will find it desirable to keep a clear correspondence (mapping) between the structure of the solution, as provided by the software, and the structure of the problem, as described by the model. Hence the first rule:

任何的軟件系統都嘗試着描述一些問題域(problem domain)的需求.如果您有一個好的模型來描述那些領域,在由軟件提供解決方案的結構和由模型所描述的問題結構之間,您將會發現保持清晰的通信(映射)是值得的.第一條規則由此而來:

 

 

 

The modular structure devised in the process of building a software system should remain compatible with any modular structure devised in the process of modeling the problem domain.

在構建一個軟件系統的過程中所設計的模塊結構應該與在問題域模型化的過程中所設計的模塊結構保持兼容.

 

 

 


 

This advice follows in particular from two of the modularity criteria:

這條建議特別遵循模塊化標準中的二條:

 

• Continuity: keeping a trace of the problem’s modular structure in the solution’s structure will make it easier to assess and limit the impact of changes.

連續性:在解決方案的結構中保存問題的模塊結構的軌跡將使評估和限定變化所造成的影響變得更容易.

 

• Decomposability: if some work has already been done to analyze the modular structure of the problem domain, it may provide a good starting point for the modular decomposition of the software.

分解性:如果某些工作已經完成了分析問題域的模塊結構,那麼對於軟件的模塊分解,它可以提供一個良好的開端.

 

Few Interfaces

少量接口

 

The Few Interfaces rule restricts the overall number of communication channels between modules in a software architecture:

少量接口的規則限制了在一個軟件架構中模塊之間的通訊頻道的全部數量:

Every module should communicate with as few others as possible.

每個模塊應該儘可能少的與其它模塊溝通.

 

 

 


 

Communication may occur between modules in a variety of ways. Modules may call each other (if they are procedures), share data structures etc. The Few Interfaces rule limits the number of such connections.

通訊可以以多種方式在模塊之間發生.模塊之間可以彼此調用(如果它們是程序),共享數據結構等等. 少量接口的規則限制了這樣的連接數量.

 

 

 


More precisely, if a system is composed of n modules, then the number of intermodule connections should remain much closer to the minimum, n–1, shown as (A) in the figure, than to the maximum, n (n – 1) /2, shown as (B).

更精確的,如果一個系統由n個模塊組成,那麼模塊之間的連接數目應該儘量保持接近最小量n–1,如(A)圖所示,而不是如(B)所示的最大值n(n – 1)/2.

 

This rule follows in particular from the criteria of continuity and protection: if there are too many relations between modules, then the effect of a change or of an error may propagate to a large number of modules. It is also connected to composability (if you want a module to be usable by itself in a new environment, then it should not depend on too many others), understandability and decomposability.

這件規則特別遵循連續性和保護性的標準:如果在模塊之間有太多關係,那麼一個變化的結果或一個錯誤可能影響到大量的模塊.它也關係到組合性(如果您想讓一個模塊在新的環境中仍然可用,那麼它不應該依賴於太多其它的模塊),理解性分解性.

 

Case (A) on the last figure shows a way to reach the minimum number of links, n – 1, through an extremely centralized structure: one master module; everybody else talks to it and to it only. But there are also much more “egalitarian” structures, such as (C) which has almost the same number of links. In this scheme, every module just talks to its two immediate neighbors, but there is no central authority. Such a style of design is a little surprising at first since it does not conform to the traditional model of functional, top-down design. But it can yield robust, extendible architectures; this is the kind of structure that object-oriented techniques, properly applied, will tend to yield.

在上圖中,情況(A)顯示了通過極端集中的結構, 達到最小鏈接數目n–1的方法:一個主模塊;每個模塊只能和它對話.但是也有更加"平行"的結構,如(C)圖,有幾乎相同數目的鏈接.在這個方案中,每個模塊僅僅和它的二個緊鄰的鄰居對話,而沒有中央的授權.由於它並不符合功能性的,由上而下的傳統設計模型,如此的設計風格起先稍微令人驚訝.但是它能產生健壯的,易擴充的架構;這種結構,適當地加工就可以產生面向對象技術的結構類型.

 

Small Interfaces

小型接口(弱耦合)

 

The Small Interfaces or “Weak Coupling” rule relates to the size of intermodule connections rather than to their number:

If two modules communicate, they should exchange as little information as possible

如果二個模塊溝通,它們應該交換儘可能少的信息.

 

 

 


小型接口弱耦合規則涉及到模塊之間連接的大小,而不是它們的數目:

 

 

An electrical engineer would say that the channels of communication between modules must be of limited bandwidth:

一個電子工程師會說,在模塊之間的通信頻道一定會被限制帶寬:

 

 


The Small Interfaces requirement follows in particular from the criteria of continuity and protection.

小型接口的需求特別的來自連續性和保護性標準.

 

An extreme counter-example is a Fortran practice which some readers will recognize: the “garbage common block”. A common block in Fortran is a directive of the form

COMMON /common_name/ variable1,¼ variablen

indicating that the variables listed are accessible not just to the enclosing module but also to any other module which includes a COMMON directive with the same common_name. It is not infrequent to see Fortran systems whose every module includes an identical gigantic COMMON directive, listing all significant variables and arrays so that every module may directly use every piece of data.

一個極端的反例是一個Fortran的習慣,一些讀者將會了解到: “垃圾公用塊.Fortran中一個公用塊如下列指令:

COMMON /common_name/ variable1,¼ variablen

表明了可被接受的變量列表, 不但是在外覆的模塊中,而且可以是包含在COMMON指令中common_name其它模塊.常會見到Fortran系統中的每一個模塊包含了一樣的巨大的COMMON,列出了所有重要的變量和數組,以至於各個模塊可以直接使用每一個數據段.

 

The problem, of course, is that every module may also misuse the common data, and hence that modules are tightly coupled to each other; the problems of modular continuity (propagation of changes) and protection (propagation of errors) are particularly nasty. This time-honored technique has nevertheless remained a favorite, no doubt accounting for many a late-night debugging session.

當然,問題是每個模塊也可能過分使用共用數據,並且導致了模塊間彼此緊密耦合;(所產生的)模塊連續性(變化的傳播)和保護性(錯誤的傳播)的問題特別地麻煩.這種由來已久的技術仍然被人樂於使用,毫無疑問地造成了許多除錯上的艱難.

 

Developers using languages with nested structures can suffer from similar troubles. With block structure as introduced by Algol and retained in a more restricted form by Pascal, it is possible to include blocks, delimited by begin ¼ end pairs, within other blocks. In addition every block may introduce its own variables, which are only meaningful within the syntactic scope of the block. For example:

開發者使用具有嵌套結構的語言忍受着相似的麻煩.Algol引入了塊結構而在Pascal保留了更多方面的限制形式,它可能在其它的塊裏面包括了被begin ¼ end分割的塊.除此之外每個塊可能聲明自己的變量,這些變量只在塊的語法範圍內纔有意義.舉例來說:

 

local-- Beginning of block B1

x, y: INTEGER

do

¼ Instructions of B1 ¼

local -- Beginning of block B2

z: BOOLEAN

do

¼ Instructions of B2 ¼

end --- of block B2

local -- Beginning of block B3

y, z: INTEGER

do

¼ Instructions of B3 ¼

end -- of block B3

¼ Instructions of B1 (continued) ¼

end -- of block B1

 

Variable x is accessible to all instructions throughout this extract, whereas the two variables called z (one BOOLEAN, the other INTEGER) have scopes limited to B2 and B3 respectively. Like x, variable y is declared at the level of B1, but its scope does not include B3, where another variable of the same name (and also of type INTEGER) locally takes precedence over the outermost y. In Pascal this form of block structure exists only for blocks associated with routines (procedures and functions).

在這段代碼中,所有的指令都可以訪問變量x,而二個被定義爲z(一個布爾類型BOOLEAN,另一個整數類型INTEGER)的變量分別地限制在B2B3塊的範圍中.像x一樣,變量yB1層次被定義,但是其訪問範圍不包括B3,這裏相同名字(也是整數類型)的另外一個變量比最上層的y在本塊具有優先權.在Pascal中,這種塊結構的形式只存在於和例程相關的區塊(程序及函數)中.

 

With block structure, the equivalent of the Fortran garbage common block is the practice of declaring all variables at the topmost level. (The equivalent in C-based languages is to introduce all variables as external.)

和塊結構一樣,與Fortran垃圾公用塊等效的是在最高的層次中聲明所有變量的動作.(以C爲基礎的語言的相似之處是以外部形式(external)定義所有的變量).

 

Block structure, although an ingenious idea, introduces many opportunities to violate the Small Interfaces rule. For that reason we will refrain from using it in the objectoriented notation devised later in this book, especially since the experience of Simula, an object-oriented Algol derivative supporting block structure, shows that the ability to nest classes is redundant with some of the facilities provided by inheritance. The architecture of object-oriented software will involve three levels: a system is a set of clusters; a cluster is a set of classes; a class is a set of features (attributes and routines). Clusters, an organizational tool rather than a linguistic construct, can be nested to allow a project leader to structure a large system in as many levels as necessary; but classes as well as features have a flat structure, since nesting at either of those levels would cause unnecessary complication.

塊結構,雖然是一個精巧的主意,但有許多地方違犯了小型接口的規則.出於這個理由,在本書後面的面向對象符號設計中,我們將盡量不使用它,尤其,由於從面嚮對象語言Algol派生出的支持塊結構的語言Simula的經驗,顯示了嵌套類的能力對一些由繼承提供的功能而言是多餘的.面向對象的軟件架構包括三個層次: 一個系統是一組羣集;一個羣集是一組類;一個類是一組特性(屬性和例程).羣集, 一個組織工具並非一個語言學結構,可以被嵌套以允許一位項目主管以儘可能多的層次構造大的系統;但是類和特性一樣只有平坦的結構,是由於在其中任何一個層次上的嵌套都會引起不必要的複雜性.

 

Explicit Interfaces

精確接口

 

With the fourth rule, we go one step further in enforcing a totalitarian regime upon the society of modules: not only do we demand that any conversation be limited to few participants and consist of just a few words; we also require that such conversations must be held in public and loudly!

Whenever two modules A and B communicate, this must be obvious from the text of A or B or both.

只要AB兩個模塊通訊, AB或兩者之間必須要有明確的文字.


有着這第四件規則,我們要更進一步,在模塊的社區裏強加上一個極權主義的政權: 我們不但要求任何會話被限制在少數的參加者之間同時只包含少量的單詞;而且我們命令這樣的會話必須保持公開和大聲!

 

Behind this rule stand the criteria of decomposability and composability (if you need to decompose a module into several submodules or compose it with other modules, any outside connection should be clearly visible), continuity (it should be easy to find out what elements a potential change may affect) and understandability (how can you understand A by itself if B can influence its behavior in some devious way?).

在這一件規則後面由分解性和組合性(如果您需要把一個模塊分解成一些子模塊或與其它的模塊合併,任何的外部連接應該清楚可見),連續性(應該很容易地發現什麼元素會被潛在的變化所影響)和理解性(如果B能以一些迂迴的方式影響A的行爲,您如何能單獨地理解A?)的標準支持着.

 

One of the problems in applying the Explicit Interfaces rule is that there is more to intermodule coupling than procedure call; data sharing, in particular, is a source of indirect coupling:

在應用精確接口的規則上,有一個問題是相比程序調用而言,存在着更多的模塊間偶合; 尤其,數據共享就是間接偶合(indirect coupling)的一個來源:


 

Assume that module A modifies and module B uses the same data item x. Then A and B are in fact strongly coupled through x even though there may be no apparent connection, such as a procedure call, between them.

假設模塊A和模塊B使用相同的數據項目x.那麼,事實上AB是通過x的強偶合,即使它們之間可能沒有像程序調用那樣的明顯的連接.

 

Information Hiding

信息隱藏

 

The rule of Information Hiding may be stated as follows:

信息隱藏的規則可以陳述如下:

The designer of every module must select a subset of the module’s properties as the official information about the module, to be made available to authors of client modules.

每個模塊的設計者必須選擇模塊屬性的一個子集作爲有關此模塊的正式信息,其可以讓客戶端模塊的作者有效使用.

 

 

 


Application of this rule assumes that every module is known to the rest of the world (that is to say, to designers of other modules) through some official description, or public properties.

這條規則的應用設想了每個模塊通過一些正式的描述,或公共的(public)屬性爲其它的世界(也就是說,對其它的模塊設計者)所知.

 

Of course, the whole text of the module itself (program text, design text) could serve as the description: it provides a correct view of the module since it is the module! The Information Hiding rule states that this should not in general be the case: the description should only include some of the module’s properties. The rest should remain non-public, or secret. Instead of public and secret properties, one may also talk of exported and private properties. The public properties of a module are also known as the interface of the module (not to be confused with the user interface of a software system).

當然,模塊的整個代碼(程序代碼,設計代碼)本身可以做爲模塊的描述:由於它模塊,所以它提供了正確的模塊視圖! 通常,信息隱藏規則表示並非如此:描述應該只包括模塊屬性中的一些.其餘的應該是非公共的,或是祕密的.取代公共和祕密的屬性,一種可以是輸出的和私有的屬性.一個模塊的公共屬性也即是模塊的接口(不要和軟件系統的用戶界面搞混[英文皆interface]).

 

The fundamental reason behind the rule of Information Hiding is the continuity criterion. Assume a module changes, but the changes apply only to its secret elements, leaving the public ones untouched; then other modules who use it, called its clients, will not be affected. The smaller the public part, the higher the chances that changes to the module will indeed be in the secret part.

在信息隱藏規則背後的基本理由是連續性標準.假設一個模塊變化了,但是變化僅應用於祕密元素,公共元素並未涉及;然後是使用它的其它模塊,稱之爲它的客戶端,也不會被影響.公共部份愈小,改變模塊的祕密部份的機會也就愈高.

 

We may picture a module supporting Information Hiding as an iceberg; only the tip — the interface — is visible to the clients.

我們可以把一個支持信息隱藏的模塊畫成像一座冰山;只有尖端接口客戶端能看得到.

 

 


 

As a typical example, consider a procedure for retrieving the attributes associated with a key in a certain table, such as a personnel file or the symbol table of a compiler. The procedure will internally be very different depending on how the table is stored (sequential array or file, hash table, binary or B-Tree etc.). Information hiding implies that uses of this procedure should be independent of the particular implementation chosen. That way client modules will not suffer from any change in implementation.

作爲一個典型的例子,考慮一段程序,在一張指定的表中取回與一關鍵字關聯的屬性,就像是在一份人事文件或編譯器的符號表中.對於不同的表儲存結構(順序數組或文件,哈希表,二進制或B樹等等.),程序在內部是不同的.信息隱藏意味着這個程序的使用應該與所選擇的特殊實現無關.那樣的話,客戶端模塊將不會受到實現方面任何改變的影響.

 

Information hiding emphasizes separation of function from implementation. Besides continuity, this rule is also related to the criteria of decomposability, composability and understandability. You cannot develop the modules of a system separately, combine various existing modules, or understand individual modules, unless you know precisely what each of them may and may not expect from the others.

信息隱藏強調從實現之中的函數分離.除了連續性之外,這一件規則也關係到分解性,組合性和理解性標準.您不能彼此分離地開發一個系統的模塊,不聯合各種不同的已存在的模塊,或不用理解單獨的模塊,除非您精確地知道它們中的每一個可能需要其它模塊的什麼或不可能需要什麼.

 

Which properties of a module should be public, and which ones secret? As a general guideline, the public part should include the specification of the module’s functionality; anything that relates to the implementation of that functionality should be kept secret, so as to preserve other modules from later reversals of implementation decisions.

一個模塊中哪些屬性應該是公共的,哪些是祕密的?作爲一個通用的方法,公共部份應該包括模塊的功能性規格;任何與功能性實現有關的應該被保持爲祕密的,這樣保護了其它模塊不會受到以後實現變化的影響.

 

This first answer is still fairly vague, however, as it does not tell us what is the specification and what is the implementation; in fact, one might be tempted to reverse the definition by stating that the specification consists of whatever public properties the module has, and the implementation of its secrets! The object-oriented approach will give us a much more precise guideline thanks to the theory of abstract data types.

然而,這最初的答案仍然是相當的模糊,它不能告訴我們什麼是規格,什麼是實現;事實上,規格由模塊的任何公共特性和祕密實現所組成的,這樣的描述可能試圖顛倒定義!由於抽象的數據類型理論,面向對象的方式將會給我們一個更加精確的引導.

 

To understand information hiding and apply the rule properly, it is important to avoid a common misunderstanding. In spite of its name, information hiding does not imply protection in the sense of security restrictions — physically prohibiting authors of client modules from accessing the internal text of a supplier module. Client authors may well be permitted to read all the details they want: preventing them from doing so may be reasonable in some circumstances, but it is a project management decision which does not necessarily follow from the information hiding rule. As a technical requirement, information hiding means that client modules (whether or not their authors are permitted to read the secret properties of suppliers) should only rely on the suppliers’ public properties. More precisely, it should be impossible to write client modules whose correct functioning depends on secret information.

爲了理解信息隱藏而且正確地應用此規則,避免一個常見的誤解是很重要的.儘管它的名字,但信息隱藏並不意味着在安全限制意義上的保護性物理上禁止客戶端模塊的作者訪問所提供之模塊的內部代碼.有充分的理由可以讓客戶端作者被允許瞭解它們想要的所有細節: 阻止它們這麼做在一些環境中可能是合理的,但是它是一個不必遵從信息藏規則的項目管理決定.正如一個技術上的需求, 信息藏意味着客戶端模塊(無論它們的作者被允許瞭解供應者的祕密特性)應該只依靠供應者的公共特性的方法.更精確的說法是,依靠祕密的信息來編寫正確函數的客戶端模塊是不可能的.

 

In a completely formal approach to software construction, this definition would be stated as follows. To prove the correctness of a module, you will need to assume some properties about its suppliers. Information hiding means that such proofs are only permitted to rely on public properties of the suppliers, never on their secret properties.

在一個軟件架構的完全正式的方法中,這個定義如下列所述.爲了要驗證模塊的正確性,您需要假定供應者的一些特性.信息藏意味着如此的證明只能依賴供應者的公共特性,而不是在它們的祕密特性上.

 

Consider again the example of a module providing a table searching mechanism. Some client module, which might belong to a spreadsheet program, uses a table, and relies on the table module to look for a certain element in the table. Assume further that the algorithm uses a binary search tree implementation, but that this property is secret — not part of the interface. Then you may or may not allow the author of the table searching module to tell the author of the spreadsheet program what implementation he has used for tables. This is a project management decision, or perhaps (for commercially released software) a marketing decision; in either case it is irrelevant to the question of information hiding. Information hiding means something else: that even if the author of the spreadsheet program knows that the implementation uses a binary search tree, he should be unable to write a client module which will only function correctly with this implementation — and would not work any more if the table implementation was changed to something else, such as hash coding.

再次考慮一個提供了表查詢機制的模塊的例子.一些客戶端模塊,可能屬於一個電子表格的程序,使用一個表,而且依賴表模塊去找查詢表中的某個元素.更進一步假定算法使用一個二進制查詢樹來實現,但是這個特性是祕密的--不是接口的一部份.然後您可能或不可能被表查詢模塊的作者允許,來告訴電子表格的作者他對錶所用了什麼樣的實現.這是一個項目管理決定,或也許(爲商業發佈的軟件)是一個行銷決定;在任何一種情況下,它對信息藏的問題都是不相關的.信息藏意味着其它的東西: 即使電子表格程序的作者知道實現使用了二進制查詢樹,他也不能夠寫一個只能正確地運行這種實現的客戶端模塊--如果表的實現改變成別的方法時,如哈希碼,就不能工作.

 

One of the reasons for the misunderstanding mentioned above is the very term “information hiding”, which tends to suggest physical protection. “Encapsulation”, sometimes used as a synonym for information hiding, is probably preferable in this respect, although this discussion will retain the more common term.

上面所提及的誤解原因之一恰恰是術語信息,它試圖暗示物理保護."封裝",有時被當作信息藏的同義字,或許在這種情況下更好,雖然這個討論將保持較通用的術語.

 

As a summary of this discussion: the key to information hiding is not management or marketing policies as to who may or may not access the source text of a module, but strict language rules to define what access rights a module has on properties of its suppliers. As explained in the next chapter, “encapsulation languages” such as Ada and Modula-2 made the first steps in the right direction. Object technology will bring a more complete solution.

討論總結:對於誰可以或不可以存取模塊的源文本,信息藏的關鍵不是管理或市場政策,但是嚴格的語言規則(language rules)定義了一個模塊在其供應者的屬性上有什麼樣的存取權限.如下章所解釋,AdaModula-2這樣的"封裝語言",做出了正確方向上的第一步.對象技術將會帶來更完整的解決方案.

 

 

3.3 FIVE PRINCIPLES

3.3 五項原則

 

From the preceding rules, and indirectly from the criteria, five principles of software construction follow:

軟件構造的五項原則從前面的規則中,並間接地從標準中而來:

 

• The Linguistic Modular Units principle. 語義模塊單元

• The Self-Documentation principle. 自包含文檔

• The Uniform Access principle. 統一存取

• The Open-Closed principle. 開閉原則

• The Single Choice principle. 單選原則

 

Linguistic Modular Units

語義模塊單元

 

The Linguistic Modular Units principle expresses that the formalism used to describe software at various levels (specifications, designs, implementations) must support the view of modularity retained:

語義模塊單元則表達了形式方法應該支持模塊化所持的觀點,這種形式方法常常在各種不同的層次(規格,設計,實現)中用於描述軟件:

Linguistic Modular Units principle

Modules must correspond to syntactic units in the language used.

所使用的程序設計語言中, 模塊應該符合語法單元.


 

The language mentioned may be a programming language, a design language, a specification language etc. In the case of programming languages, modules should be separately compilable.

被提到的語言可以是程序語言,設計語言,規格語言等等.在程序語言的情況中,模塊應該可以單獨編譯.

 

What this principle excludes at any level — analysis, design, implementation — is combining a method that suggests a certain module concept and a language that does not offer the corresponding modular construct, forcing software developers to perform manual translation or restructuring. It is indeed not uncommon to see companies hoping to apply certain methodological concepts (such as modules in the Ada sense, or object-oriented principles) but then implement the result in a programming language such as Pascal or C which does not support them. Such an approach defeats several of the modularity criteria:

在任何層次(分析,設計,實現)中,這項原則所排斥的內容,正在聯合一個方法迫使軟件開發者進行手動轉化或更改結構,這個方法建議了一個並不提供相應的模塊化結構的某種模塊概念和語言.我們可以看到許多公司正在希望應用某種方法學上的概念(Ada中的模塊,或面向對象的原則)但是接着在並不支持這些概念的設計語言中實現其結果,諸如PascalC這樣的語言.這種情況當然並不罕見.這樣的方式違反了一些模塊化的標準:

 

• Continuity: if module boundaries in the final text do not correspond to the logical decomposition of the specification or design, it will be difficult or impossible to maintain consistency between the various levels when the system evolves. A change of the specification may be considered small if it affects only a small number of specification modules; to ensure continuity, there must be a direct correspondence between specification, design and implementation modules.

連續性: 如果在最終的代碼中,模塊界線不符合規格或設計的邏輯分解性,那麼在系統進展中,在各種不同的層次之間維持一致性將會變得困難,或者根本不可能.如果一個規格的變化隻影響小部分的規格模塊,那麼這可能會被認爲無關緊要;爲了確保連續性,在規格,設計和實現模塊之間必須有直接對應.

 

• Direct Mapping: to maintain a clear correspondence between the structure of the model and the structure of the solution, you must have a clear syntactical identification of the conceptual units on both sides, reflecting the division suggested by your development method.

直接映射: 爲了要在模型結構和解決方案結構之間維持一個清晰的通訊,您必須要在兩者之間有一個清晰的概念單元的語法統一,以反映被您的開發方法所要求劃分.

 

• Decomposability: to divide system development into separate tasks, you need to make sure that every task results in a well-delimited syntactic unit; at the implementation stage, these units must be separately compilable.

分解性: 爲了要把系統開發分割爲單獨的任務,您需要確定每個任務正好是一個獨立的語法單元;在實現的階段,這些單元要能獨立的編譯.

 

• Composability: how could we combine anything other than modules with unambiguous syntactic boundaries?

組合性: 我們如何能把除了有清晰語法界線的模塊之外的任何事物結合起來?

 

• Protection: you can only hope to control the scope of errors if modules are syntactically delimited.

保護性: 如果模塊是按依照語法分割的,您只能希望控制錯誤的範圍了.

 

Self-Documentation

自包含文檔

 

Like the rule of Information Hiding, the Self-Documentation principle governs how we should document modules:

就象信息隱藏的規則, 自包含文檔原則決定了我們應該如何對模塊寫文檔:

Self-Documentation principle

The designer of a module should strive to make all information about the module part of the module itself.

模塊的設計者應該努力讓模塊的本身包含其所有的信息.

 

 


               

What this precludes is the common situation in which information about the module is kept in separate project documents.

這排除了模塊信息保存在單獨的項目文檔中的一般情況.

 

The documentation under review here is internal documentation about components of the software, not user documentation about the resulting product, which may require separate products, whether paper, CD-ROM or Web pages — although, as noted in the discussion of software quality, one may see in the modern trend towards providing more and more on-line help a consequence of the same general idea.

在這裏所討論的文檔是有關軟件組件的內部文檔,不是最終產品的用戶手冊,手冊可以是單獨的產品,不管是紙,光盤或網頁--然而,如軟件品質所討論的,一個可以看到的現代趨勢是提供越來越多的在線幫助.

 

The most obvious justification for the Self-Documentation principle is the criterion of modular understandability. Perhaps more important, however, is the role of this principle in helping to meet the continuity criterion. If the software and its documentation are treated as separate entities, it is difficult to guarantee that they will remain compatible — “in sync” — when things start changing. Keeping everything at the same place, although not a guarantee, is a good way to help maintain this compatibility.

自包含文檔原則最明顯的理由是模塊的理解性標準.然而,也許更重要是其在幫助符合連續性標準方面所起的作用.如果軟件和它的文檔被當作獨立的實體,那麼當事物開始變更的時候,保證它們會兼容"在同步中"是很困難的.保持所有的事物同一進度,雖然這不是一個保證,但是這是幫助維持兼容性的一個好方法.

 

Innocuous as this principle may seem at first, it goes against much of what the software engineering literature has usually suggested as good software development practices. The dominant view is that software developers, to deserve the title of software engineers, need to do what other engineers are supposed to: produce a kilogram of paper for every gram of actual deliverable. The encouragement to keep a record of the software construction process is good advice — but not the implication that software and its documentation are different products.

起先,這項原則可能看上去沒有什麼負作用,它反對許多軟件工程文獻通常所建議的良好的軟件開發實踐.權威的觀點是軟件開發者,要得到軟件工程師的頭銜的話,需要去做其他工程師們所應該做的:爲每一克實際所交付的東西生產一公斤的紙.鼓勵保存軟件構造過程的記錄是個好的忠告但並不意味着軟件和它的文檔是不同的產品.

 

Such an approach ignores the specific property of software, which again and again comes back in this discussion: its changeability. If you treat the two products as separate, you risk finding yourself quickly in a situation where the documentation says one thing and the software does something else. If there is any worse situation than having no documentation, it must be having wrong documentation.

上述方式忽視了一次又一次反覆討論的軟件的特定屬性:它的可變性.如果把二種產品獨立來看,您會發現您處在這樣的一種冒險的境地:在文檔裏說這件事而軟件卻在做其它事.如果這裏有比沒有文檔更糟糕的情形的話,那一定是錯誤的文檔.

 

A major advance of the past few years has been the appearance of quality standards for software, such as ISO certification, the “2167” standard and its successors from the US Department of Defense, and the Capability Maturity Model of the Software Engineering Institute. Perhaps because they often sprang out of models from other disciplines, they tend to specify a heavy paper trail. Several of these standards could have a stronger effect on software quality (beyond providing a mechanism for managers to cover their bases in case of later trouble) by enforcing the Self-Documentation principle.

過去幾年中一個主要的進步是軟件品質標準(quality standards)的出現,像是ISO認證,

2167標準和來自美國國防部的後繼版本,軟件工程學會的能力成熟度模型(CMM).也許因爲它們從來自其它的訓練模型裏跳出的,所以它們趨向於指定詳細的書面材料.這些標準中的一些通過加強自包含文檔原則在軟件品質上有着更好的效果(這超越了以防後面的麻煩單純爲管理人員提供一個機制的出發點).

 

This book will draw on the Self-Documentation principle to define a method for documenting classes — the modules of object-oriented software construction — that includes the documentation of every module in the module itself. Not that the module is its documentation: there is usually too much detail in the software text to make it suitable as documentation (this was the argument for information hiding). Instead, the module should contain its documentation.

本書將會利用自包含文檔原則來定義一個方法,這個方法爲了文檔類面向對象軟件構造的模塊模塊自身中包括了每個模塊的文.並不是模塊就是它的文: 通常在軟件文本中有太多的細節使其不適合成爲文(這也是信息隱藏的論據).作爲替代的,模塊應該包含它的文.

 

In this approach software becomes a single product that supports multiple views. One view, suitable for compilation and execution, is the full source code. Another is the abstract interface documentation of each module, enabling software developers to write client modules without having to learn the module’s own internals, in accordance with the rule of Information Hiding. Other views are possible.

在這種方式中,軟件變成了一種支持多重觀點(views)的單一產品.一種適合編譯和執行的觀點認爲是完整的源程序代碼.另外一種認爲是每個模塊的抽象接口文,並促成軟件開發者編寫客戶端模塊而不必學習模塊自身的內在結構,這符合信息隱藏的規則.其它的觀點都有可能存在.

 

We will need to remember this rule when we examine the question of how to document the classes of object-oriented software construction.

當我們檢驗該如何編寫面向對象軟件構造的類文這樣的問題時,我們需要牢記這條規則.

 

Uniform Access

統一存取

 

Although it may at first appear just to address a notational issue, the Uniform Access principle is in fact a design rule which influences many aspects of object-oriented design and the supporting notation. It follows from the Continuity criterion; you may also view it as a special case of Information Hiding.

雖然它起先出現可能只是用於描述一個符號上的議題,但是事實上,統一存取的原則是一條影響面向對象設計和支持符號的多方面的設計規則.它遵循連續性標準;您也可以把它看作信息隱藏的一個特別情況.

 

Let x be a name used to access a certain data item (what will later be called an object) and f the name of a feature applicable to x. (A feature is an operation; this terminology will also be defined more precisely.) For example, x might be a variable representing a bank account, and f the feature that yields an account’s current balance. Uniform Access addresses the question of how to express the result of applying f to x, using a notation that does not make any premature commitment as to how f is implemented.

x爲存取某個數據項目(稍後將會被稱之爲一個對象)的變量名,f爲應用於x上的一個特性名.(一個特性就是一個運算;這一術語也將會更精確地定義.)舉例來說,x可能是一個表示銀行賬戶的變量,f是產生賬戶當前餘額的特性.統一存取描述了該如何表示xf應用的結果的問題,對於f如何實現,並使用了一個不作任何的過早約定的符號.

 

In most design and programming languages, the expression denoting the application of f to x depends on what implementation the original software developer has chosen for feature f: is the value stored along with x, or must it be computed whenever requested? Both techniques are possible in the example of accounts and their balances:

在大多數的設計和程序語言中, xf應用的表達式依賴於最初的軟件開發者對特性f選擇了什麼樣實現: 數值是連同x一起儲存的,還是每當請求的時候必須要再次計算? 在這個賬戶和餘額的例子中這兩種技術都是有可能的:

 

A1 • You may represent the balance as one of the fields of the record describing each account, as shown in the figure. With this technique, every operation that changes the balance must take care of updating the balance field.

A1: 您可以用記錄中的字段之一來表達餘額,這些記錄描述了每一條賬戶,如下圖所示.這樣的話, 每一個改變餘額的運算必須要更新餘額字段.

 

A2 • Or you may define a function which computes the balance using other fields of the record, for example fields representing the lists of withdrawals and deposits. With this technique the balance of an account is not stored (there is no balance field) but computed on demand.

A2:或者,您可以定義一個函數,使用記錄中的其它字段來計算餘額,例如,字段表達了提款和存款的清單.使用此技術,賬戶的餘額沒有被儲存(這裏並沒有餘額字段)但是在需要時計算.

 

 


 

A common notation, in languages such as Pascal, Ada, C, C++ and Java, uses x. f in case A1 and f (x) in case A2.

Pascal, Ada, C, C++Java等語言中, A1中用x. f 符號,A2中用f (x)符號.

 

Choosing between representations A1 and A2 is a space-time tradeoff: one economizes on computation, the other on storage. The resolution of this tradeoff in favor of one of the solutions is typical of representation decisions that developers often reverse at least once during a project’s lifetime. So for continuity’s sake it is desirable to have a feature access notation that does not distinguish between the two cases; then if you are in charge of x’s implementation and change your mind at some stage, it will not be necessary to change the modules that use f. This is an example of the Uniform Access principle.

在A1和A2表示法之間的選擇是一個時間空間上的折衷:一個節約在計算上,另一個在儲存上.在解決方案中選其一,這種折衷決定是具有代表性的決定,在項目週期中開發者曾經常反覆至少一次.因此,爲了連續性的緣故,如果有一個特性能在不區別這二種情況下進行存取,那麼這是極有價值的;然後如果您負責x的實現,並且在某個階段時改變了自己的想法,這就不必改變使用f的模塊.這是統一存取原則的一個例子.

 

In its general form the principle may be expressed as:

統一存取原則的通用形式可表達如下:

 

 

Uniform Access principle

All services offered by a module should be available through a uniform notation, which does not betray whether they are implemented through storage or through computation.

一個模塊所提供的所有服務應該是通過一個統一的符號被使用,其不會泄漏出它們是通過存儲還是經過計算而實現的.

 

 


Few languages satisfy this principle. An older one that did was Algol W, where both the function call and the access to a field were written a (x). Object-oriented languages should satisfy Uniform Access, as did the first of them, Simula 67, whose notation is x. f in both cases. The notation developed in part C will retain this convention.

很少的語言能滿足這項原則.一個較舊的語言Algol W,把功能調用和字段存取都寫成a(x).面向對象的語言應該滿足統一存取原則,如同第一個語言Simula 67,在兩種情況下符號都是x. f. 在本書C部分中,符號開發將會保持這個約定.

 

The Open-Closed principle

開閉原則

 

Another requirement that any modular decomposition technique must satisfy is the Open-Closed principle:

模塊分解技術必須滿足的另一個需求是開閉原則:

Open-Closed principle

Modules should be both open and closed.

模塊應該都能開放(open)和關閉(closed).


 

The contradiction between the two terms is only apparent as they correspond to goals of a different nature:

在二個術語之間的矛盾只有在當它們符合不同目標的時候纔出現:

 

• A module is said to be open if it is still available for extension. For example, it should be possible to expand its set of operations or add fields to its data structures.

如果一個模塊一直能有效地擴充,那麼它被說成是開放.比如,其有可能擴充它的運算集合或把字段加入到它的數據結構中.

 

• A module is said to be closed if it is available for use by other modules. This assumes that the module has been given a well-defined, stable description (its interface in the sense of information hiding). At the implementation level, closure for a module also implies that you may compile it, perhaps store it in a library, and make it available for others (its clients) to use. In the case of a design or specification module, closing a module simply means having it approved by management, adding it to the project’s official repository of accepted software items (often called the project baseline), and publishing its interface for the benefit of other module authors.

如果一個模塊被其它的模塊有效的使用,那麼它被說成是關閉.這裏假設模塊已經給予了明確的定義,穩定的描述(其接口已有信息隱藏的能力).在實現的層次上,關閉一個模塊也意味着您可以編譯它,或許儲存在一個庫中,並且使其它模塊(它的客戶端)可以有效使用.對於設計模塊或規格模塊來說,關閉一個模塊只是意味着被管理層覈准了,作爲公用的軟件條目(時常被稱爲項目基準(baseline))把它加入到項目的正式軟件包中,而且對其它的模塊的作者公佈其接口.

 

The need for modules to be closed, and the need for them to remain open, arise for different reasons. Openness is a natural concern for software developers, as they know  that it is almost impossible to foresee all the elements — data, operations — that a module will need in its lifetime; so they will wish to retain as much flexibility as possible for future changes and extensions. But it is just as necessary to close modules, especially from a project manager’s viewpoint: in a system comprising many modules, most will depend on some others; a user interface module may depend on a parsing module (for parsing command texts) and on a graphics module, the parsing module itself may depend on a lexical analysis module, and so on. If we never closed a module until we were sure it includes all the needed features, no multi-module software would ever reach completion: every developer would always be waiting for the completion of someone else’s job.

關閉模塊和保持開放的需求,因爲不同的理由而出現.公開是軟件開發者自然地考慮,因爲它們知道,幾乎不可能預見一個模塊在它的週期中所需要的所有元素 數據,運算;因此它們願爲將來的變化和擴充保持儘可能多的彈性.但是正如必需要關閉模塊一樣,尤其是項目經理的觀點:一個系統中包含了大量的模塊,大部分將會依賴於其它的一些;一個用戶接口模塊可能依賴一個解析(parsing)模塊(爲了解析指令文本)和一個圖形模塊,那個解析模塊本身可能依賴於一個語法分析模塊,等等.如果我們從不關閉一個模塊直到我們確定它包含了所有的需要特性的話,那麼,多模塊軟件就永遠不會完成:每個開發者會總是會等候其他人的工作先完成.

 

With traditional techniques, the two goals are incompatible. Either you keep a module open, and others cannot use it yet; or you close it, and any change or extension can trigger a painful chain reaction of changes in many other modules, which relied on the original module directly or indirectly.

由於傳統的技術,這二個目標是相互矛盾的.或者您保持一個模塊開放,其它的模塊仍然不能夠使用它;或者您關閉它,任何的變化或擴充能引起痛苦的連鎖反應,許多其它的模塊都需要改變,它們直接地或間接地依賴最初的模塊.

 

The two figures below illustrate a typical situation where the needs for open and closed modules are hard to reconcile. In the first figure, module A is used by client modules B, C, D, which may themselves have their own clients (E, F, ¼).

下面的兩幅圖闡明瞭一個典型的情況,需要開放和關閉的模塊很難融合.在第一幅圖中, 模塊A被客戶端模塊B,C,D使用,它們自己也有客戶端(E, F, ¼).

 


Later on, however, the situation is disrupted by the arrival of new clients — B' and others — which need an extended or adapted version of A, which we may call A':

可是稍後,情形被新來的B’和其它的客戶端打亂了,新客戶端需要一個擴充的或改編的A版本,我們叫它A’:

 

 


With non-O-O methods, there seem to be only two solutions, equally unsatisfactory:

不用OO的方式,這裏看上去只有兩種解決方案, 不令人滿意:

 

N1 • You may adapt module A so that it will offer the extended or modified functionality (A' ) required by the new clients.

N1. 您可以改編A模塊,這樣將提供給新客戶端所需要的擴充或修改功能性(A').

 

N2 • You may also decide to leave A as it is, make a copy, change the module’s name to A' in the copy, and perform all the necessary adaptations on the new module. With this technique A' retains no further connection to A.

N2. 您可以決定留下A,拷貝並改名爲A’,在新模塊中完成所有必須的改編. 這樣一來,A’就不和A有更進一步的關係了.

 

The potential for disaster with solution N1 is obvious. A may have been around for a long time and have many clients such as B, C and D. The adaptations needed to satisfy the new clients’ requirements may invalidate the assumptions on the basis of which the old ones used A; if so the change to A may start a dramatic series of changes in clients, clients of clients and so on. For the project manager, this is a nightmare come true: suddenly, entire parts of the software that were supposed to have been finished and sealed off ages ago get reopened, triggering a new cycle of development, testing, debugging and documentation. If many a software project manager has the impression of living the Sisyphus syndrome — the impression of being sentenced forever to carry a rock to the top of the hill, only to see it roll back down each time — it is for a large part because of the problems caused by this need to reopen previously closed modules.

方案N1的潛在災禍很明顯.A可能已經被訪問了很長的一段時間並且有許多B,CD這樣的客戶端.改編需要滿足新客戶端的需求,這些改編假設在使用A的舊客戶端的基礎上是無效的;假如這樣的話,A的改變可能會引發顯著的一系列方面的改變,客戶端的改變,客戶端之客戶端的改變等等.對於項目經理,這真是噩夢成真:突然,已經完成而且之前就封版的整個軟件又要重新開始,並引發了又一輪新的週期:開發,測試,除錯和編寫文檔.如果多數軟件項目經理有着逼真的西西弗斯(Sisyphus)併發症狀的感覺被判決永遠地將一塊岩石攜帶到小山頂,每次只能看到它滾下的感覺這大部份是因爲要重新開放先前關閉的模塊的問題所造成的.

[希臘神話:西西弗斯, 希臘古時科林斯殘暴的國王,因作惡多端,死後墮入地獄,被判以永遠將一塊巨石推上海蒂斯的一座小山,而每當接近山頂時,石頭又會滾下來]

 

On the surface, solution N2 seems better: it avoids the Sisyphus syndrome since it does not require modifying any existing software (anything in the top half of the last figure). But in fact this solution may be even more catastrophic since it only postpones the day of reckoning. If you extrapolate its effects to many modules, many modification requests and a long period, the consequences are appalling: an explosion of variants of the original modules, many of them very similar to each other although never quite identical.

表面上,方案N2似乎更好一點:由於它不需要修改任何的已存在的軟件(在最後一副圖的頂部上的一切),它避免了西西弗斯併發症狀.但是事實上這個解決方案甚至更悲慘,它只是延遲了發作的時間而已.如果您對許多模塊和修改請求使用同樣的結果,在一段時間後,其結果令人心驚膽顫:最初模塊的變體呈爆炸性增長, 它們大部分彼此非常相似但又不完全相同.

 

In many organizations, this abundance of modules, not matched by abundance of available functionality (many of the apparent variants being in fact quasi-clones), creates a huge configuration management problem, which people attempt to address through the use of complex tools. Useful as these tools may be, they offer a cure in an area where the first concern should be prevention. Better avoid redundancy than manage it.

在許多組織中,這種模塊豐富度並沒有和有效的功能性的豐富度相匹配(許多明顯的變體事實上是準克隆),這產生了一個極大的配置管理(configuration management)問題,人們嘗試通過使用複雜的工具來描述它們.由於這些工具是有效的,所以它們對某個領域提供了治療方法.但這個領域首要關注的應是預防.對於管理冗餘來說,更好的是避免它.

 

 

Configuration management will remain useful, of course, if only to find the modules which must be reopened after a change, and to avoid unneeded module recompilations.

當然,如果僅僅是找出必須在一個變化之後重新開放的模塊和避免不需要的模塊再次編輯,配置管理將會一直有效.

 

But how can we have modules that are both open and closed? How can we keep A and everything in the top part of the figure unchanged, while providing A' to the bottom clients, and avoiding duplication of software? The object-oriented method will offer a particularly elegant contribution thanks to inheritance.

但是我們如何能有同時開閉的模塊?當提供A'給底部的客戶端的時候, 我們如何能保持A和一切在圖形頂端的部份不變,同時避免軟件的複製? 面向對象的方法提供一個特別優秀的方法:繼承.

 

The detailed study of inheritance appears in later chapters, but here is a preview of the basic idea. To get us out of the change or redo dilemma, inheritance will allow us to define a new module A' in terms of an existing module A by stating the differences only. We will write A' as

繼承的詳細研究在後的章介紹,這裏是基本概念的一個預覽.爲了要使我們避免變化(change)(redo)困境, 繼承允許我們已存在的模A定義一個新的模A',描述不同部分.我們A’:

 

class A'  inherit

A redefine f, g, ¼ end

feature

f is ¼

g is ¼

¼

u is ¼

¼

end

 

where the feature clause contains both the definition of the new features specific to A', such as u, and the redefinition of those features (such as f, g, ¼) whose form in A' is different from the one they had in A.

這裏,特性子句包含了A’中新的特性定義,u ,和重定義的那些A中有的卻又不同於A的特性(f, g, ¼.)     

 

The pictorial representation for inheritance will use an arrow from the heir (the new class, here A') to the parent (here A):

繼承的圖示使用了從繼承者(新類,A’)到父親(A)的一個箭頭:

 

 

 

 

 

 

 

 

 


 

Thanks to inheritance, O-O developers can adopt a much more incremental approach to software development than used to be possible with earlier methods.

由於繼承,OO的開發者能採用一種比過去所用的老式方法更加增量的軟件開發方式.

 

One way to describe the open-closed principle and the consequent object-oriented techniques is to think of them as a organized hacking. “Hacking” is understood here as a slipshod approach to building and modifying code (not in the more recent sense of breaking into computer networks, which, organized or not, no one should condone). The hacker may seem bad but often his heart is pure. He sees a useful piece of software, which is almost able to address the needs of the moment, more general than the software’s original purpose. Spurred by a laudable desire not to redo what can be reused, our hacker starts modifying the original to add provisions for new cases. The impulse is good but the effect is often to pollute the software with many clauses of the form if that_special_case then¼, so that after a few rounds of hacking, perhaps by a few different hackers, the software starts resembling a chunk of Swiss cheese that has been left outside for too long in August (if the tastelessness of this metaphor may be forgiven on the grounds that it does its best to convey the presence in such software of both holes and growth).

一種描述開閉原則和相關的面向對象技術的方法是把它們想成是有組織的黑客行爲(organized hacking).在這裏,黑客行爲可以理解成構建和修改代碼的一種隨意的方式(不是我們所知道的黑客:闖進計算機網絡裏,有組織或非組織,一個不能寬恕之人).黑客看上去很壞但是他卻心地純潔.他查看一個有效的軟件片段,幾乎能夠在片刻間描述出需求,比軟件的原始目的更全面.不需要做些重複的東西來獲得讚賞,我們的黑客開始修改原代碼以加入新的需求.良好的願望但是效果卻大打折扣,軟件被許多if that_special_case then¼這樣形式的子句所污染,所以在一些回合之後,也許是一些不同的黑客所爲,軟件開始類似於在八月份的天氣下放在外面很長時間的一大塊瑞士奶酪(如果當場無法理解這個比喻可以原諒,它在盡最大的努力去表達這樣一個具有千瘡百孔和膨脹的軟件).

 

The organized form of hacking will enable us to cater to the variants without affecting the consistency of the original version.

黑客行爲的組織形式使我們能夠不影響最初版本的穩定而迎合變體.

 

A word of caution: nothing in this discussion suggests disorganized hacking. In particular:

注意:這裏沒有討論破壞黑客行爲.尤其是:

 

• If you have control over the original software and can rewrite it so that it will address the needs of several kinds of client at no extra complication, you should do so.

如果您能控制最初的軟件並能重寫它,以便它會在沒有額外的複雜化的情況下描述幾種客戶端的需求,那麼您應該這麼做。

 

• Neither the Open-Closed principle nor redefinition in inheritance is a way to address design flaws, let alone bugs. If there is something wrong with a module, you should fix it — not leave the original as it is and try to correct the problem in a derived module. (The only potential exception to this rule is the case of flawed software which you are not at liberty to modify.) The Open-Closed principle and associated techniques are intended for the adaptation of healthy modules: modules that, although they may not suffice for some new uses, meet their own well-defined requirements, to the satisfaction of their own clients.

既不是開閉原則也不是在繼承中重新定義,這是描述設計缺點並忽略錯誤的一個方法.如果一個模塊有些錯誤,您應該修改它不是留在原來的代碼中而且試着在派生模塊中改正.(對這條規則的唯一潛在的例外情況是您無權修改有缺點的軟件.)開閉原則和相關的技術試圖改編健全的模塊:雖然這些模塊不能滿足一些新的用法,但符合它們自己的明確定義的需求,並滿足於它們自己的客戶端.

 

Single Choice

單選

 

The last of the five modularity principles may be viewed as a consequence of both the Open-Closed and Information Hiding rules.

作爲開閉和信息隱藏規則的推論,我們來研究五項模塊性原則的最後一個.

 

Before examining the Single Choice principle in its full generality, let us look at a typical example. Assume you are building a system to manage a library (in the nonsoftware sense of the term: a collection of books and other publications, not software modules). The system will manipulate data structures representing publications. You may have declared the corresponding type as follows in Pascal-Ada syntax:

在研究單選原則的完整概論之前,讓我們看着一個典型的例子.假如您正在建造一個系統來管理一個庫(以非軟件化的術語來說:書和其它出版物的一個集合,不是軟件模塊).系統將會操縱數據結構來表現該出版物.您可能已經聲明對應的類型,如下面的Pascal-Ada語法:

 

type PUBLICATION =

record

author, title: STRING;

publication_year: INTEGER

case pubtype: (book, journal, conference_proceedings) of

book: (publisher: STRING);

journal: (volume, issue: STRING);

proceedings: (editor, place: STRING) -- Conference proceedings

end

 

This particular form uses the Pascal-Ada notion of “record type with variants” to describe sets of data structures with some fields (here author, title, publication_year) common to all instances, and others specific to individual variants.

這種特別的形式使用Pascal-Ada"記錄型變量(record type with variants)",描述一些字段(author, title, publication_year)數據結構集合,對所有的實例和其它個別的變量都共用的.

 

The use of a particular syntax is not crucial here; Algol 68 and C provide an equivalent mechanism through the notion of union type. A union type is a type T defined as the union of pre-existing types A, B, ¼: a value of type T is either a value of type A, or a value of type B, ¼ Record types with variants have the advantage of clearly associating a tag, here book, journal, conference_proceedings, with each variant.

這裏,特殊語法使用重要;Algol68C提供了提供一個相的機制,聯合類型(union type).一個聯合類型一個類T,被定義爲已存在的類型A,B,..的聯合體: T值是A值,或B的值, 記錄型變量有一點好處是可以清楚地表達聯合的標記,這裏book, journal, conference_proceedings,個變.

 

Let A be the module that contains the above declaration or its equivalent using another mechanism. As long as A is considered open, you may add fields or introduce new variants. To enable A to have clients, however, you must close the module; this means that you implicitly consider that you have listed all the relevant fields and variants. Let B be a typical client of A. B will manipulate publications through a variable such as

p: PUBLICATION

and, to do just about anything useful with p, will need to discriminate explicitly between the various cases, as in:

case p of

book: ¼ Instructions which may access the field p l publisher ¼

journal: ¼ Instructions which may access fields p l volume, pl issue ¼

proceedings: ¼ Instructions which may access fields p l editor, pl place ¼

end

A爲一個模塊,包含了上述的聲明或使用了其它機制的類似聲明.在A是開放狀態的時候,您可以增加字段或引進新的變量.然而,爲使客戶端能用A,您一定關閉模塊;這意謂您要絕對考慮您已經列出的所有有關的字段和變量.設BA的一個典型的客戶端.B將會通過如下變量來處理出版物

p: PUBLICATION

並且,要使p對所有出版物都有效,需要在各種不同的情況中明確地加以區別,如下所示:

case p of

book: ¼ Instructions which may access the field p l publisher ¼

journal: ¼ Instructions which may access fields p l volume, pl issue ¼

proceedings: ¼ Instructions which may access fields p l editor, pl place ¼

end

 

The case instruction of Pascal and Ada comes in handy here; it is of course on purpose that its syntax mirrors the form of the declaration of a record type with variants. Fortran and C will emulate the effect through multi-target goto instructions (switch in C). In these and other languages a multi-branch conditional instruction (if ¼ then ¼ elseif ¼ elseif ¼ else ¼ end) will also do the job.

這裏,Pascal和Ada的case指令正好派上用場;當然這是特意讓它的語法反映了記錄型變量的聲明形式.FortranC將會通過多層goto的方法來效仿這種指令的效果(C中的switch語句).在這些和其它的語言中,一個多分支條件語句(if ¼ then ¼ elseif¼ elseif ¼ else ¼ end)也會做這樣的工作.

 

Aside from syntactic variants, the principal observation is that to perform such a discrimination every client must know the exact list of variants of the notion of publication supported by A. The consequence is easy to foresee. Sooner or later, you will realize the need for a new variant, such as technical reports of companies and universities. Then you will have to extend the definition of type PUBLICATION in module A to support the new case. Fair enough: you have modified the conceptual notion of publication, so you should update the corresponding type declaration. This change is logical and inevitable. Far harder to justify, however, is the other consequence: any client of A, such as B, will also require updating if it used a structure such as the above, relying on an explicit list of cases for p. This may, as we have seen, be the case for most clients.

除了語法的變化之外,主要的結果是爲了執行這樣的一種鑑別能力,每個客戶端一定要知道A所支持的出版物變量的精確的列表.其結果可以輕易地預見到.遲早您會有新變化的需求,像是公司和大學的技術報告.然後,您不得不擴充模塊A中的PUBLICATION的定義以支持新的情況.這足夠合理: 您已經修改了出版物概念上的理解,因此,您應該更新對應的類型聲明.這個變化合乎邏輯並不可避免.然而,更困難的是要想驗證另一個結果:如果用瞭如上的結構,依賴於出版物變化情況的精確列表的話,象B這樣的任何A的客戶端也需要更新.如我們所見,可能大多數的客戶端都能遇上這樣的情況.

 

What we observe here is a disastrous situation for software change and evolution: a simple and natural addition may cause a chain reaction of changes across many client modules.

在這裏,我們所觀察的是軟件變化和演化中的一種災難性的情形:一個簡單自然的增加可能會引發橫跨許多客戶端模塊的一個連鎖反應.

 

The issue will arise whenever a certain notion admits a number of variants. Here the notion was “publication” and its initial variants were book, journal article, conference proceedings; other typical examples include:

每當某個觀念接納了許多的變量,問題就將出現了.這裏的觀念是出版物,其初始變量是書,期刊文章,會議紀要;其它的典型例子包括:

 

• In a graphics system: the notion of figure, with such variants as polygon, circle, ellipse, segment and other basic figure types.

一個圖形系統: 圖形的概念,包含這些變量,如多角形,圓周,橢圓,線段和其它的基本圖形類型.

 

• In a text editor: the notion of user command, with such variants as line insertion, line deletion, character deletion, global replacement of a word by another.

一個文字編輯器: 用戶指令的概念,包含這些變量,如行插入,行刪除,字符刪除,詞組的全部替換.

 

• In a compiler for a programming language, the notion of language construct, with such variants as instruction, expression, procedure.

一個程式設計語言的編譯器:語言構造的概念,包含這些變量,如指令,表達式,程序.

 

In any such case, we must accept the possibility that the list of variants, although fixed and known at some point of the software’s evolution, may later be changed by the addition or removal of variants. To support our long-term, software engineering view of the software construction process, we must find a way to protect the software’s structure against the effects of such changes. Hence the Single Choice principle:

在所有的這些例子中,我們必須接受這些可能性,變量的清單雖然在軟件演化的某些時候是固定和已知的,但以後可能會被增加或刪除.爲了支持長期的,軟件構造過程的軟件工程觀點,我們必須要找到一個方法來保護軟件結構,避免如此變化的結果.單選原則由此而來:

 

Single Choice principle

Whenever a software system must support a set of alternatives, one and only one module in the system should know their exhaustive list.

每當一個軟件系統必須支持一組替代選擇,那麼在系統中有且只有一個模塊知道它們的詳細列表.

 

 

 


By requiring that knowledge of the list of choices be confined to just one module, we prepare the scene for later changes: if variants are added, we will only have to update the module which has the information — the point of single choice. All others, in particular its clients, will be able to continue their business as usual.

依照選擇的列表定義只限制在一個模塊中的需求,我們爲稍後的變化準備了佈景: 如果變量增加,我們只是必須更新表明單選信息的模塊.所有其它的,特別是其客戶端,能夠一切如常.

 

Once again, as the publications example shows, traditional methods do not provide a solution; once again, object technology will show the way, here thanks to two techniques connected with inheritance: polymorphism and dynamic binding. No sneak preview in this case, however; these techniques must be understood in the context of the full method.

再一次,如出版物例子所示,傳統的方法並沒有提供解決方案;這裏,由於二種與繼承相關的技術:多態和動態綁定,對象技術將再一次展示其方式.然而,在這種情況下沒有定式,這些技術一定要在完整方法的上下文中才能瞭解.

 

The Single Choice principle prompts a few more comments:

單選原則提示了一些更多的解釋:

 

• The number of modules that know the list of choices should be, according to the principle, exactly one. The modularity goals suggest that we want at most one module to have this knowledge; but then it is also clear that at least one module must possess it. You cannot write an editor unless at least one component of the system has the list of all supported commands, or a graphics system unless at least one component has the list of all supported figure types, or a Pascal compiler unless at least one component “knows” the list of Pascal constructs.

依照此原則,知道選擇列表的模塊數目應該是完全唯一的.模塊化的目標建議我們最多一個模塊擁有這些定義;不過,它也清楚的表明至少一個模塊一定持有它.您不能夠編寫一個編輯器除非至少系統的一個組件有全部支持指令的列表,或不能夠編寫一個圖形系統除非至少一個組件有全部的圖形類型列表,也不能夠編寫一個Pascal編譯器除非至少一個組件"知道"Pascal構造的列表.

 

• Like many of the other rules and principles studied in this chapter, the principle is about distribution of knowledge in a software system. This question is indeed crucial to the search for extendible, reusable software. To obtain solid, durable system architectures you must take stringent steps to limit the amount of information available to each module. By analogy with the methods employed by certain human organizations, we may call this a need-to-know policy: barring every module from accessing any information that is not strictly required for its proper functioning.

如同在這章中學習的大部份其它的規則和原則,這項原則是有關於在一個軟件系統中的知識分配(distribution of knowledge).這個問題毫無疑問地對探索可擴充的,可複用的軟件起着決定性作用.爲了要獲得堅固持久的系統架構,您必須採取迫切的步驟來限制每個模塊可用的信息數量.根據某些人類組織僱用人員的方法,我們可以稱這爲需要-去-知道(need-to-know)策略:禁止每個模塊存取任何信息,這些信息對它正當的功能並沒有嚴格地要求.

 

• You may view the Single Choice principle as a direct consequence of the Open-Closed principle. Consider the publications example in light of the figure that illustrated the need for open-closed modules: A is the module which includes the original declaration of type PUBLICATION; the clients B, C, ¼ are the modules that relied on the initial list of variants; A' is the updated version of A offering an extra variant (technical reports).

您可能把單選原則看作開閉原則的直接結果.根據描繪開閉模塊需求的插圖考慮出版物的例子: A是包括類型PUBLICATION最初聲明的模塊; 客戶端B,C.. 是依賴於變量初始列表的模塊;A'A的更新版本,提供了一個額外的變量(技術上的陳述).

 

• You may also understand the principle as a strong form of Information Hiding. The designer of supplier modules such as A and A' seeks to hide information (regarding the precise list of variants available for a certain notion) from the clients.

您也可以把原則理解成信息隱藏的強化形式.提供模塊(如AA’)的設計者尋求自客戶端的信息隱藏(當作從一個特定觀念的有效變量的精確列表).

 

 

3.4 KEY CONCEPTS INTRODUCED IN THIS CHAPTER

 

• The choice of a proper module structure is the key to achieving the aims of reusability and extendibility.

一個適當的模塊結構的選擇是達成複用性和擴充性目標的關鍵.

 

• Modules serve for both software decomposition (the top-down view) and software composition (bottom-up).

模塊爲軟件分解性(由上而下的觀點)和軟件組合性(由下而上的觀點)服務.

 

• Modular concepts apply to specification and design as well as implementation.

模塊的概念適用於規格設計,也適用於實現.

 

• A comprehensive definition of modularity must combine several perspectives; the various requirements may sometimes appear at odds with each other, as with decomposability (which encourages top-down methods) and composability (which favors a bottom-up approach).

一個全面的模塊化定義必須要結合幾種觀點;由於分解性(鼓勵由上而下的方法)和組合性(支持由下而上的方式),各種不同的需求有時可能出現彼此不一致的現象.

 

• Controlling the amount and form of communication between modules is a fundamental step in producing a good modular architecture.

在模塊之間控制通訊數量和形式是產生一個好的模塊架構的基本步驟.

 

• The long-term integrity of modular system structures requires information hiding, which enforces a rigorous separation of interface and implementation.

模塊化系統結構的長期完整性需要信息隱藏,信息隱藏實施在接口和實現之間的嚴格分離.

 

• Uniform access frees clients from internal representation choices in their suppliers.

統一存取從其供應者的內部表示法選擇中釋放了客戶端.

 

• A closed module is one that may be used, through its interface, by client modules.

一個關閉模塊是一個通過它的接口,可以被客戶端模塊所使用的模塊.

 

• An open module is one that is still subject to extension.

一個開放模塊是一個一直需要擴充的模塊.

 

• Effective project management requires support for modules that are both open and closed. But traditional approaches to design and programming do not permit this.

高效的項目管理需要支持模塊的開放或關閉.但是傳統的設計和編程方法並不允許這樣做.

 

• The principle of Single Choice directs us to limit the dissemination of exhaustive knowledge about variants of a certain notion.

單選原則指導我們限制對確定觀念的變量的全面定義進行傳播.

 

 

3.5 BIBLIOGRAPHICAL NOTES

The design method known as “structured design” [Yourdon 1979] emphasized the importance of modular structures. It was based on an analysis of module “cohesion” and “coupling”. But the view of modules implicit in structured design was influenced by the traditional notion of subroutine, which limits the scope of the discussion.

The principle of uniform access comes originally (under the name “uniform reference”) from [Geschke 1975].

The discussion of uniform access cited the Algol W language, a successor to Algol 60 and forerunner to Pascal (but offering some interesting mechanisms not retained in Pascal), designed by Wirth and Hoare and described in [Hoare 1966].

Information hiding was introduced in two milestone articles by David Parnas [Parnas 1972] [Parnas 1972a].

Configuration management tools that will recompile the modules affected by modifications in other modules, based on an explicit list of module dependencies, are based on the ideas of the Make tool, originally for Unix [Feldman 1979]. Recent tools —there are many on the market — have added considerable functionality to the basic ideas.

Some of the exercises below ask you to develop metrics to evaluate quantitatively the various informal measures of modularity developed in this chapter. For some results in O-O metrics, see the work of Christine Mingins [Mingins 1993] [Mingins 1995] and Brian Henderson-Sellers [Henderson-Sellers 1996a].

 

EXERCISES

 

E3.1 Modularity in programming languages

Examine the modular structures of any programming language which you know well and assess how they support the criteria and principles developed in this chapter.

 

E3.2 The Open-Closed principle (for Lisp programmers)

Many Lisp implementations associate functions with function names at run time rather than statically. Does this feature make Lisp more supportive of the Open-Closed principle than more static languages?

 

E3.3 Limits to information hiding

Can you think of circumstances where information hiding should not be applied to relations between modules?

 

E3.4 Metrics for modularity (term project)

The criteria, rules and principles of modularity of this chapter were all introduced through qualitative definitions. Some of them, however, may be amenable to quantitative analysis.

The possible candidates include:

• Modular continuity.

• Few Interfaces.

• Small Interfaces.

• Explicit Interfaces.

• Information Hiding.

• Single Choice.

Explore the possibility of developing modularity metrics to evaluate how modular a software architecture is according to some of these viewpoints. The metrics should be size-independent: increasing the size of a system without changing its modular structure should not change its complexity measures. (See also the next exercise.)

 

E3.5 Modularity of existing systems

Apply the modularity criteria, rules and principles of this chapter to evaluate a system to which you have access. If you have answered the previous exercise, apply any proposed modularity metric.

Can you draw any correlations between the results of this analysis (qualitative, quantitative or both) and assessments of structural complexity for the systems under study, based either on informal analysis or, if available, on actual measurements of debugging and maintenance costs?

 

E3.6 Configuration management and inheritance

(This exercise assumes knowledge of inheritance techniques described in the rest of this book. It is not applicable if you have read this chapter as part of a first, sequential reading of the book.)

The discussion of the open-closed principle indicated that in non-object-oriented approaches the absence of inheritance places undue burden on configuration management tools, since the desire to avoid reopening closed modules may lead to the creation of too many module variants. Discuss what role remains for configuration management in an object-oriented environment where inheritance is present, and more generally how the use of object technology affects the problem of configuration management.

If you are familiar with specific configuration management tools, discuss how they interact with inheritance and other principles of O-O development.

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