外觀模式

2018-08-12 21:55 更新

外觀模式 - Facade

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

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

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

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

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

如何使用外觀模式

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

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

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

LibraryAPI 會(huì)暴露給其他代碼訪問(wèn),但是 PersistencyManagerHTTPClient 則是不對(duì)外開(kāi)放的。

打開(kāi) LibraryAPI.swift 然后添加如下代碼:

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

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

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

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

  super.init()
}

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

接下來(lái)在 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:) 這個(gè)方法,先更新本地緩存,然后如果是聯(lián)網(wǎng)狀態(tài)還需要向服務(wù)器發(fā)送網(wǎng)絡(luò)請(qǐng)求。這便是外觀模式的強(qiáng)大之處:如果外部文件想要添加一個(gè)新的專(zhuān)輯,它不會(huì)也不用去了解內(nèi)部的實(shí)現(xiàn)邏輯是怎么樣的。

注意:當(dāng)你設(shè)計(jì)外觀的時(shí)候,請(qǐng)務(wù)必牢記:使用者隨時(shí)可能直接訪問(wèn)你的隱藏類(lèi)。永遠(yuǎn)不要假設(shè)使用者會(huì)遵循你當(dāng)初的設(shè)計(jì)做事。

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

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

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)