世上一直有一個神話:設計可以並且應該獨立於實現的細節,設計通常被看作是一個抽象的概念而實現是一個代碼的具體執行個體。如果我們堅信"設計是一個富有創造性和目的性的活動:為某一個目標而精心制定的結構的概念,",一個結構如果不能夠說明它的環境,或者不能與環境協作,那麼這個結構就不適合這一目標。環境中包括目標平台--語言、工具、庫、中介軟體(middleware),等。還有它的功能性和非功能性的單元。
我們會認為在不知道地形布局的時候設計房屋,或者在不清楚使用的道材料的時候建造摩天大廈是不合理的事情。我們將線程、分布這類概念看作為小的編碼的細節的看法無疑是在設計中導致浪費精力(時間和金錢)的導火索,最終我們發現的是理論與實踐的差距在實踐中要比在理論中還大。雖然在一些情況下一個高層次設計的某部分可以在許多技術下保持不變,但是更多的情況是我們需要親自來補足這個圓圈,允許(甚至鼓勵)細節和實際的資訊來影響並告知系統的結構。
模式(Patterns)的作用就是擷取這些結構上的資訊。它們可以描述--預見性的或回顧性的--設計和設計的原理,講述從問題到解決,說明環境,擷取工作的動力以及應此產生的結果。這裡,我將集中講述兩個模式--Command-Query Separation和Command Method--為一個類介面中的方法分配任務,考察他們如何互相作用並影響並發的、分布的和有序的環境以及本地執行。
介面設計。顧名思義,介面提供了不同系統之間或者系統不同組件之間的界定。在軟體中,介面提供了一個屏障,從而從實現中分離了目標,從具體中分離了概念,從作者中分離了使用者。在Java中,有許多介面的概念:public部分為潛在的使用者提供了類和方法的介面,protected部分為它的子類(subclass)以及周圍的包提供了一個介面;一個包有一個公用的部分;反射(Reflection)是另外一種提供、使用對象方法介面的機制。
約束及供給。站在使用者對作者的角度,一個介面建立並命名了一個目的模型的使用方法。類介面中的方法提供了一種特殊的使用方法。是這些約束--編譯時間的類型系統,運行是的異常機制及傳回值--使得類作者的目的得以體現和加強。在這方面最簡單的例子是對封裝的意義的理解:私人化可以保證類使用者只可以通過類的公用方法介面來操作資訊和行為。
然而,對於封裝來說,遠不止資料私人那麼簡單。在設計中,封裝往往會涉及到自我包含(self-containment)。一個需要你知道如何調用一個方法(e.g."在一個線程的環境中,在一個方法調用後調用另一個方法,你必須明確地同步對象")的類的封裝就不如將所有這些全部包含並隱藏的類(e.g."這個類是thread-safe的")好。前一個設計存在著設計的漏洞,它的許多限定條件是模糊的而不是經過加強的。這就把責任推給了使用者而不是讓類提供者做這些工作來完成類的設計,並且,這是不可避免的漏洞百出。
在這種情況下,供給(affordances)描述了使用的可行性和不可行性。
術語供給(affordances)指事物的被感知的真實的屬性,首先,這些屬性可以決定事物的使用的可能方法。一個椅子可以用來支撐其他東西,所以,可以坐人。一個椅子照樣可以搬運(carried)。玻璃可以透光,也可以被打碎……
供給提供了對事物操作的線索,板狀物可以壓、柄狀物可以旋轉,溝狀物可以插入東西。球狀物可以扔或者反彈。當使用了供給的優勢後,使用者可以只通過看便確定該做什麼:沒有圖、沒有標籤也沒有說明。複雜的事物可能會需要一些解釋,但是簡單的事物不應該這樣。當簡單的東西也需要用圖片、標籤來說明的時候,設計就是失敗的。
類設計者的一個職責便是在介面中減小約束與供給之間的隔閡(gap),匹配目標以及一定程度上的自由度,儘可能減小錯誤使用的可能。
對環境敏感的設計。在空間或者時間上分離方法的執行--例如,線程,遠程方法調用,訊息佇列--能夠對設計的正確性和效率產生意義深遠的影響。這種分離帶來的結果是不可忽視的:並發引入了不確定性和環境選擇的開銷;分布引入了錯誤的和不斷增加的回程的調用開銷。這些是設計的問題,而不是修改bug那樣簡單。
無論是在何種情況下,結果都是將會阻礙所有權風格的程式設計(Property-Style Programming)--當一個介面主要由set和get方法組成的時候,每個方法都相應的直接指向私人地區。這樣的類的封裝很差(意思是毫無遮掩)。介面中的域訪問器(Field accessors)通常是不會提供資訊的:他們在對象的使用中不能通訊、簡單化和抽象化,這通常會導致冗長並易出現錯誤的代碼。所有權風格的程式設計在短時間內不是一個大的活動。分布和並行通過引入了正確性和嚴重的效能開銷放大了這些格式上實踐的問題。
透明度和bug災難。抽象允許我們在必要的時候可以忽略細節,所以我們的設計思想可以平衡環境的因素而不是受制於它們。決定什麼樣的細節可以忽略便成為一個挑戰。問題的嚴重性在重要的細節別忽略的情況下上升了。
設計往往會盡量使環境因素儘可能的透明。透明能夠成為一個誘人的主意:也許它可以讓線程和遠程對象通訊完全透明,這樣使用者在進行對象通訊的時候什麼也不會覺察到。Proxy模式支援一定程度上的透明度。這加強了RMI和COBRA的基礎。本地的代理的對象和使用遠端對象在使用中具有相同的介面,並且編組上的細節允許調用著使用熟悉的方法來調用模型。然而,這種分布透明並不完全:失誤和潛在的影響,不能被完全隱藏並且需要考慮。畢竟透明不是毛巾。