鍍金池/ 教程/ iOS/ 外觀模式 - Facade
開始
裝飾者模式 - Decorator
單例模式 - Singleton
外觀模式 - Facade
觀察者模式 - Observer
準備工作
iOS 設(shè)計模式
適配器模式 - Adapter
備忘錄模式 - Memento
最后的潤色
小結(jié)
設(shè)計模式之王- MVC

外觀模式 - Facade

http://wiki.jikexueyuan.com/project/ios-design-patterns-in-swift/images/1.7.jpg" alt="" />

外觀模式在復雜的業(yè)務(wù)系統(tǒng)上提供了簡單的接口。如果直接把業(yè)務(wù)的所有接口直接暴露給使用者,使用者需要單獨面對這一大堆復雜的接口,學習成本很高,而且存在誤用的隱患。如果使用外觀模式,我們只要暴露必要的 API 就可以了。

下圖演示了外觀模式的基本概念:

http://wiki.jikexueyuan.com/project/ios-design-patterns-in-swift/images/1.8.png" alt="" />

API 的使用者完全不知道這內(nèi)部的業(yè)務(wù)邏輯有多么復雜。當我們有大量的類并且它們使用起來很復雜而且也很難理解的時候,外觀模式是一個十分理想的選擇。

外觀模式把使用和背后的實現(xiàn)邏輯成功解耦,同時也降低了外部代碼對內(nèi)部工作的依賴程度。如果底層的類發(fā)生了改變,外觀的接口并不需要做修改。

舉個例子,如果有一天你想換掉所有的后臺服務(wù),你只需要修改 API 內(nèi)部的代碼,外部調(diào)用 API 的代碼并不會有改動。

如何使用外觀模式

現(xiàn)在我們用 PersistencyManager 來管理專輯數(shù)據(jù),用 HTTPClient 來處理網(wǎng)絡(luò)請求,項目中的其他類不應(yīng)該知道這個邏輯。他們只需要知道 LibraryAPI 這個"外觀"就可以了。

為了實現(xiàn)外觀模式,應(yīng)該只讓 LibraryAPI 持有 PersistencyManagerHTTPClient 的實例,然后 LibraryAPI 暴露一個簡單的接口給其他類來訪問,這樣外部的訪問類不需要知道內(nèi)部的業(yè)務(wù)具體是怎樣的,也不用知道你是通過 PersistencyManager 還是 HTTPClient 獲取到數(shù)據(jù)的。

大致的設(shè)計是這樣的:

http://wiki.jikexueyuan.com/project/ios-design-patterns-in-swift/images/1.9.png" alt="" />

LibraryAPI 會暴露給其他代碼訪問,但是 PersistencyManagerHTTPClient 則是不對外開放的。

打開 LibraryAPI.swift 然后添加如下代碼:

private let persistencyManager: PersistencyManager
private let httpClient: HTTPClient
private let isOnline: Bool

除了兩個實例變量之外,還有個 Bool 值: isOnline ,這個是用來標識當前是否為聯(lián)網(wǎng)狀態(tài)的,如果是聯(lián)網(wǎng)狀態(tài)就會去網(wǎng)絡(luò)獲取數(shù)據(jù)。

我們需要在 init 里面初始化這些變量:

override init() {
  persistencyManager = PersistencyManager()
  httpClient = HTTPClient()
  isOnline = false

  super.init()
}

HTTPClient 并不會直接和真實的服務(wù)器交互,只是用來演示外觀模式的使用。所以 inOnline 這個值我們一直設(shè)置為 false。

接下來在 LibraryAPI.swift 里添加如下代碼:

func getAlbums() -> [Album] {
  return persistencyManager.getAlbums()
}

func addAlbum(album: Album, index: Int) {
  persistencyManager.addAlbum(album, index: index)
  if isOnline {
    httpClient.postRequest("/api/addAlbum", body: album.description())
  }
}

func deleteAlbum(index: Int) {
  persistencyManager.deleteAlbumAtIndex(index)
  if isOnline {
    httpClient.postRequest("/api/deleteAlbum", body: "(index)")
  }
}

看一下 addAlbum(_:index:) 這個方法,先更新本地緩存,然后如果是聯(lián)網(wǎng)狀態(tài)還需要向服務(wù)器發(fā)送網(wǎng)絡(luò)請求。這便是外觀模式的強大之處:如果外部文件想要添加一個新的專輯,它不會也不用去了解內(nèi)部的實現(xiàn)邏輯是怎么樣的。

注意:當你設(shè)計外觀的時候,請務(wù)必牢記:使用者隨時可能直接訪問你的隱藏類。永遠不要假設(shè)使用者會遵循你當初的設(shè)計做事。

運行一下你的應(yīng)用,你可以看到兩個空的頁面和一個工具欄:最上面的視圖用來展示專輯封面,下面的視圖展示數(shù)據(jù)列表。

http://wiki.jikexueyuan.com/project/ios-design-patterns-in-swift/images/1.10.png" alt="" />

你需要在屏幕上展示專輯數(shù)據(jù),這是就該用下一種設(shè)計模式了:裝飾者模式。