iOS設計模式之代理模式

語言: CN / TW / HK

持續創作,加速成長!這是我參與「掘金日新計劃 · 6 月更文挑戰」的第20天,點選檢視活動詳情

本文主要介紹iOS設計模式中的代理模式,代理模式顧名思義是通過控制對另一些物件的訪問,相當中間添加了一箇中間類來訪問物件。

1. 什麼是代理模式

比如我們一般登陸一些會員制的網站,通常一些功能只有會員才能訪問,普通使用者只能訪問一些基礎的內容,付費內容則需要充值會員才能訪問。那麼和代理模式有啥關係,代理的一個常見用處是作為一個輕量的替身物件,它運去客戶端首先訪問一些廉價的資訊或功能,知道充值會員才提供付費的資源。因此代理在一開始向用戶提供試用會員資格,當用戶願意為真正的高價的會員資格付費的時候,代理會敞開大門讓使用者訪問付費會員的功能。
信用卡是銀行賬戶的代理, 銀行賬戶則是一大捆現金的代理。 它們都實現了同樣的介面, 均可用於進行支付。 消費者會非常滿意, 因為不必隨身攜帶大量現金; 商店老闆同樣會十分高興, 因為交易收入能以電子化的方式進入商店的銀行賬戶中, 無需擔心存款時出現現金丟失或被搶劫的情況。
通常帶路模式有以下一些代理 - [ ] 遠端代理:為位於不同地址空間或網路上的物件提供本地代表。 - [ ] 虛擬代理:更具需要建立重型物件。 - [ ] 保護代理: 更具各種訪問許可權控制原物件的訪問 - [ ] 智慧引用代理: 通過對真正物件的引用進行計數來管理記憶體。也用於鎖定真正物件,讓其他物件不能對其進行修改。

代理模式:為其他物件提供一種代理以控制對這個物件的訪問。

2. 什麼時候使用代理模式

下面的情形可以考慮使用代理模式 - [ ] 需要一個遠端代理,為位於不同地址空間或網路中的物件提供本地代表 - [ ] 需要一個虛擬代理,來根據要求建立重型的物件。 - [ ] 需要一個保護代理,來根據不同訪問許可權控制對原物件的訪問。 - [ ] 需要一個智慧引用代理,通過對實體物件的引用進行計算來管理記憶體。

3. 程式碼展示

```Swift import XCTest

/// The Subject interface declares common operations for both RealSubject and /// the Proxy. As long as the client works with RealSubject using this /// interface, you'll be able to pass it a proxy instead of a real subject. protocol Subject {

func request()

}

/// The RealSubject contains some core business logic. Usually, RealSubjects are /// capable of doing some useful work which may also be very slow or sensitive - /// e.g. correcting input data. A Proxy can solve these issues without any /// changes to the RealSubject's code. class RealSubject: Subject {

func request() {
    print("RealSubject: Handling request.")
}

}

/// The Proxy has an interface identical to the RealSubject. class Proxy: Subject {

private var realSubject: RealSubject

/// The Proxy maintains a reference to an object of the RealSubject class.
/// It can be either lazy-loaded or passed to the Proxy by the client.
init(_ realSubject: RealSubject) {
    self.realSubject = realSubject
}

/// The most common applications of the Proxy pattern are lazy loading,
/// caching, controlling the access, logging, etc. A Proxy can perform one
/// of these things and then, depending on the result, pass the execution to
/// the same method in a linked RealSubject object.
func request() {

    if (checkAccess()) {
        realSubject.request()
        logAccess()
    }
}

private func checkAccess() -> Bool {

    /// Some real checks should go here.

    print("Proxy: Checking access prior to firing a real request.")

    return true
}

private func logAccess() {
    print("Proxy: Logging the time of request.")
}

}

/// The client code is supposed to work with all objects (both subjects and /// proxies) via the Subject interface in order to support both real subjects /// and proxies. In real life, however, clients mostly work with their real /// subjects directly. In this case, to implement the pattern more easily, you /// can extend your proxy from the real subject's class. class Client { // ... static func clientCode(subject: Subject) { // ... print(subject.request()) // ... } // ... }

/// Let's see how it all works together. class ProxyConceptual: XCTestCase {

func test() {
    print("Client: Executing the client code with a real subject:")
    let realSubject = RealSubject()
    Client.clientCode(subject: realSubject)

    print("\nClient: Executing the same client code with a proxy:")
    let proxy = Proxy(realSubject)
    Client.clientCode(subject: proxy)
}

} ```

4.小結

在iOS中我們有一個NSProxy類,NSProxy類實現了NSObject協議,所以NSProxy物件實際上也是NSObject型別。NSProxy類是一個抽象基類。代理模式會將所有實際工作委派給一些其他物件。 除非代理是某個服務的子類, 否則每個代理方法最後都應該引用一個服務物件