模式解決OO設計者日常必須面對的問題:
尋找適當的對象:模式協助你界定(identify)一些不明顯(less-obvious)的屬性(abstractions)而使的對象得以撷取他們。這些對象在分析或者是設計初期並不是很明顯的;而是在設計成比較彈性或者可重復使用時才逐漸浮現。
決定對象的細致程度(granularity):對象在數量及大小可以是兩極化;他可能是小到處理硬件的單元但數量極多;或者單一個極大對象像一個運用程序(application)。所以如何決定一個對象的尺寸便成為一個議題。模式可以協助你去定義對象的細致程度。外觀(Facade)描述如何將一個子系統以一個對象來表示。輕量(Flyweight)描述如何支持一個大數量但細小的對象。其它模式則描述特殊方法如何分解一個對象成更細小的對象。抽象工廠(Abstract Factory)及建設者(Builder)產生的對象其責任只是產生其它的對象。訪問者(Visitor)及指令(Command)產生的對象其責任只是實現對其它對象的需求。
說明(specifying)對象的接口:每一個對象宣告多個操作(Operation),每個操作都有一個名稱,對象以操作名稱當作參數並在運算後傳回值;此為操作的特征(signature)。這些特征復合成對象的接口(interface)。對象的接口可以提供外界對此對象的請求(request),只要這些請求符合這個對象的特征就可以為此對象接受。
型別(type)是用來表示部分(particular)的接口。例如若某對象接受一個名叫「Windows」接口的定義的操作的所有請求;則此對象稱為有此「Windows」型別。一個對象可有許多型別;而可有許多不同的對象共有一個型別。對象的接口可以區分為各種型別。兩各對象只要部分接口相同則可稱此兩對象為相同型別。接口可以包含其它接口(subset)。如果一個型別的接口包含(contains)其祖型別(supertype)的界面則稱此型別為子型別(subtype);也就是說子型別繼承祖型別的接口。
當一個對象接受請求;其實際操作必須依據其請求及接收的對象;不同的對象接收同一請求可能有不同的實現來響應這個請求,這種在執行期(run-time)復合請求及對象的方式稱為動態連結(dynamic binding)。動態連結意味著所有請求必須自執行期才會確定他的實現。動態連結讓你在執行期替代不同的對象但有相同的接口;這種替代稱為多型(polymorphism)。如此可讓提出請求的對象(clIEnt)無須因不同接收請求的對象而改變請求的形式或方式;而讓提出請求的對象簡單化;並且降低對象間的鏈接關系(couple);及讓它們之間的關系在執行期可以動態的改變。
模式協助你定義接口;經由界定(identify)他們的關鍵元素(key element)及經由接口互傳數據的種類。模式也可能告訴你哪些不要放到接口中。
模式同時說明接口間的關系,有時他們會請求某些類要有相似的接口或者在接口上做某些限制。
裝飾者(Decorator)及代理(Proxy)要求其對象必須與其受裝飾或代理的對象有相同的接口。訪問者(Visitor)的接口必須反應(reflect)其可訪問的對象的所有類。
說明對象的實現: 說明對象的實現:
抽象類(abstract class)主要是為其子類定義一般共同(common)接口。抽象類一般會讓子類部份或全部實現其界面;因此抽象類無法建立對象(instantiate)。抽象類未實現的操作(Operation)稱為抽象操作(abstract Operations)。反之非抽象類則稱為具體類(concrete class)。子類可以定義或重新定義父類的行為此種改變主類操作的方式稱為覆寫(override)。
類繼承及接口繼承:
一個對象的型別只是與其接口有關也就是說它可以響應某一組的需求;一個對象可以有許多型別而不同類的對象可以有相同的型別。類定義對象可執行的操作及其型別;所以我們說一個對象是某類的對象實例(instance)也就是說它支持此類的接口。
類繼承定義一個對象的實現也就是說程序代碼(code)及外觀(representation),而接口繼承描述一個對象可以替代另一個對象(有相同的接口)。
類繼承及接口繼承可能會混淆因為在某些語言並不是做很明顯的區分。C++的繼承表示接口及實現兩者同時繼承,若只要接口繼承就是繼承只有純粹虛擬函數(pure virtual member functions)的類;類是繼承C++的純粹抽象類(pure abstract class)。
雖然大部分程序語言並不區分類繼承及接口繼承;但是有實在實務上必須去區分。例如C++程序設計師利用抽象類來定義型別。
許多模式依賴這兩著的區別;例如責任鏈(Chain of Responsibility Pattern)必須有一共同(common)的型別但是他們常常不共享實現。復合(Composite Pattern)其成員定義一個共享的接口但是復合則定義一個共同的實現。指令(Command)、觀察者(Observer)、狀態(State)及策略(Strategy)則常常實現成只有純粹接口的抽象類。
為接口寫程序,不是實現(Programming to a Interface, not a Implementation)
類繼承的機制主要是經由再使用(reusing)其組類的功能來擴展運用程序的功能,他幾乎讓你無限制得擴展新的功能同時繼承現存類既有的功能。此外繼承的功能同時能夠定義一群具有相同接口的對象(一般從抽象類繼承);其重要性是如此才能有多型(polymorphism)的功能。
所有從一抽象模擬別繼承之子類會共享此抽象類的接口;子類只是加入或覆寫操作同時也未隱藏組類的操作。因此所有子類可以承擔此抽象類定義的接口可響應的請求。其利益有二:
1.客戶(clIEnt)可以不必他使用這個對象的型別;只要知道這個對象支持客戶請求的接口。
2.客戶可以不知道實現這個對象的類;只要知道此抽象類定義的接口即可。如此可以大大降低子系統之間實現的相依性;如此可以產生再使用OO設計的第一個定理:
為接口寫程序,不只是去實現(Programming to a Interface, not a Implementation)
不必宣告某特定具體類的對象實例變量(不必從具體類產生對象);只要確認是某抽象類定義所需要的接口即可(只需考慮此抽象類定義的接口是否符合即可)。