這部分與其用接口適配來形容,也可以說是接口設(shè)計。涉及到接口適配的有以下三種設(shè)計模式,
① 適配器(為了適配舊接口)
② 橋接(為了適配不同的接口)
③ 外觀模式(為了接口簡單好用)
一. 適配器
適配器模式是用來解決已有類與新的接口不兼容的情況,將一個類的接口轉(zhuǎn)換成客戶希望的另一個接口。有兩種實現(xiàn)適配器的方法:類適配器和對象適配器。
類適配器是通過繼承實現(xiàn)的。因為OC不支持多繼承,Target只能以協(xié)議形式存在。Adapter遵守Target協(xié)議,繼承Adaptee。Target協(xié)議定義了對外的接口(request方法)。Adapter沒有重載Adaptee的specificRequest方法,而是在request方法的實現(xiàn)中,調(diào)用父類(Adaptee)的specificRequest方法。

與類適配器不同,對象適配器不繼承被適配者,而是組合了一個對它的引用,從“屬于”變成了“包含”。在request方法的實現(xiàn)中,調(diào)用了[adaptee specificRequest]。

這兩種方式的適配器達(dá)成的目是一樣的,只是各自的特征和試用范圍有所差異。我們需要根據(jù)具體的需求去選擇。

cocoa框架中的委托模式就是適配器模式的一種實現(xiàn)。適配器模式是為了把類的接口變換為客戶端要求的另一個接口。在委托中,客戶端是cocoa Touch框架中的類,Target是委托協(xié)議,實現(xiàn)協(xié)議的具體類就是適配器,應(yīng)用程序中的其他類就是被適配者(與框架不匹配需要適配)。
舉個例子??:控制器上有個tableview,控制器遵守tableview的dataSource協(xié)議,實現(xiàn)dataSource協(xié)議中的方法,比如獲取rows數(shù)量(從數(shù)組的count獲?。?。在這里,dataSource協(xié)議就是Target,tableview是客戶端,控制器是適配器,數(shù)組對象就是被適配者。
用協(xié)議和代碼塊實現(xiàn)的適配器的角色是不一樣的,我們可以通過書中的例子及對應(yīng)的分析圖看出來。


委托模式也可以實現(xiàn)其他設(shè)計模式,比如裝飾模式,模板模式。在模板方法中包含一套預(yù)定義的參數(shù)化的算法,留出某些特定行為要求子類來提供,但是在這些情況下特定行為是委托。模板方法的執(zhí)行中,必要時會想委托(適配器)發(fā)送消息以請求某些特定行為,然后通過適配器(委托)的接口,從應(yīng)用程序中的被適配者獲取任何特定信息。所以,委托模式用于多個設(shè)計模式的混合體與其相互關(guān)聯(lián)的情況很常見。
在以下情況,需要考慮使用適配器模式:
(1)已有類的接口與需求不匹配。
(2)想要一個可復(fù)用的類,該類能夠同可能帶有不兼容接口的其他類協(xié)作。
(3)需要適配一個類的幾個不同子類,可是讓每一個子類去子類化一個類適配器又不現(xiàn)實。那么可以使用對象適配器(委托)來適配其父類的接口。
二. 橋接
橋接模式用于幫助消除抽象接口與實現(xiàn)的耦合,從而接口可以獨立的進行變更。橋接模式把抽象層次結(jié)構(gòu)從實現(xiàn)中分離出來,使其可以獨立變更,抽象層定義了供客戶端使用的上層抽象接口,實現(xiàn)層次結(jié)構(gòu)定義了供抽象層次使用的底層接口,實現(xiàn)類的引用被封裝于抽象層的實例中,橋接就形成了。
其實,就是抽象的管理類管理一個抽象的執(zhí)行類,通過一個方法或者多個方法來讓抽象執(zhí)行類完成功能,這就是傳說中的橋接模式。換句話說,就是管理類和執(zhí)行類是不同的層次結(jié)構(gòu),但是通過對象組合關(guān)系,在兩個層次結(jié)構(gòu)的上層抽象類之間形成“橋接”,從而聯(lián)系起來。
如類圖所示,Abstraction定義了供客戶端使用的上層抽象接口的父接口。它有一個對Implementor實例的引用,Implementor定義了實現(xiàn)類的接口。Implementor的接口提供基礎(chǔ)操作,而Abstraction的上層操作基于這些基礎(chǔ)操作。當(dāng)客戶端向Abstraction的實例發(fā)送operation消息時,這個方法向imp發(fā)送operationImp消息。底下的實際ConcreteImplementator(A或B)做出響應(yīng)。
當(dāng)想往系統(tǒng)添加新的ConcreteImplementator時,所要做的只是為Implementor創(chuàng)建出一個新的實現(xiàn)類,這對Abstraction方面沒有任何影響。同樣,想要修改Abstraction的接口或者創(chuàng)建更細(xì)化的Abstraction類,也不會影響到Implementor這頭。(去掉一頭的抽象不就是對象適配器了嗎?)

舉個例子??:小時候有兩款游戲機(GameBoy和GameGear),我們現(xiàn)在需要在完全不同的硬件體系結(jié)構(gòu)的臺式機和iOS設(shè)備上運行。consoleController和ConsoleEmulator分別是虛擬控制器和仿真器的抽象類。我們操縱虛擬控制器,實際執(zhí)行的是仿真器。通過這樣的設(shè)計,我們加上安卓設(shè)備或者GameXX都是相當(dāng)容易的。

對于適配器模式,適配器其實主要是適配一個接口,而橋接模式是為了適配到不同接口。
在以下情況,需要考慮使用橋接模式:
(1)不想在抽象與其實現(xiàn)之間形成固定的綁定關(guān)系(這樣就可以再運行時切換實現(xiàn))。
(2)抽象及其實現(xiàn)都應(yīng)可以通過子類化獨立進行擴展。
(3)對抽象的實現(xiàn)修改不應(yīng)影響客戶端代碼。
(4)如果每個實現(xiàn)需要額外的子類以細(xì)化抽象,則說明有必要把它們分成兩部分。
(5)想在帶有不同抽象接口的多個對象之間共享一個實現(xiàn)。
三. 外觀模式
外觀模式能夠把不同的接口組合起來,而且可以把它們簡化成單一入口,就像建筑的外觀(大門)一樣。外觀模式為子系統(tǒng)中一組不同的接口提供了統(tǒng)一的接口,外觀定義了上層接口,通過降低復(fù)雜度和隱藏子系統(tǒng)之間的通信及依存關(guān)系,讓子系統(tǒng)更易于使用。
比方說子系統(tǒng)有一組不同的類,其中一些彼此依賴,如下圖所示。這讓客戶端很難使用子系統(tǒng)中的類,因為客戶端需要知道每一個類。有時如果客戶端只是需要子系統(tǒng)的某些基本行為,而對子系統(tǒng)的類不做太多定制,外觀為這樣的客戶端提供了簡化的入口。

舉個例子??:以整個坐出租車為例,出租車服務(wù)作為一個封閉的系統(tǒng),包括出租車司機(Driver)、出租車(Car)和計時器(Taximeter)。一旦乘客向司機發(fā)出driveToLocation:x消息,Driver就會收到這個消息,操作兩個子系統(tǒng)。Driver會啟動Taximeter,讓它開始計價,然后讓汽車進行換擋、踩油門等操作。到達(dá)目的地后,Driver會松油門,踩剎車,停止Taximeter。無論這兩個系統(tǒng)多負(fù)責(zé),乘客只負(fù)責(zé)提供Driver一個driveToLocation:x的信息。所以說Driver充當(dāng)?shù)耐庥^類。

當(dāng)程序逐漸變大變復(fù)雜時,會有越來越小型的類從設(shè)計和應(yīng)用模式中演化出來。如果沒有一種簡化的方式來使用這些類,客戶端代碼將變得越來越大、越來越難理解。外觀有助于提供一種更為簡潔的方式來使用子系統(tǒng)的這些類。處理這些子系統(tǒng)類的默認(rèn)行為的,可能只是定義在外觀中的一個簡單的方法,而不必直接去使用這些類。
在以下情況,需要考慮使用外觀模式:
(1)子系統(tǒng)正逐漸變得復(fù)雜。應(yīng)用模式的過程中演化出許多類。可以使用外觀為這些子系統(tǒng)類提供一個較簡單的接口。
(2)可以使用外觀對子系統(tǒng)進行分層。每個子系統(tǒng)級別有一個外觀作為入口點。讓它們通過其外觀進行通信,可以簡化它們的依賴關(guān)系。