Proxy – Design Patterns in Swift

Introduction

Proxy is a structural design pattern that provides an object that acts as a substitute for a real service object used by a client. Consider that, when accessing sensitive objects, for example, it should be possible to check that clients have the needed access rights. As a result, this pattern solves two problems. One is the access to an object should be controlled. The other is additional functionality should be provided when accessing an object.

Proxy Pattern – UML

Use Proxy Pattern in Swift

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

    init(_ realSubject: RealSubject) {
        self.realSubject = realSubject
    }

    func request() {

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

    private func checkAccess() -> Bool {

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

        return true
    }

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

And it maintains a reference to an object of the RealSubject class. The most common applications of this 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.

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)
    }
}

Conclusion

In summary, Proxies delegate all of the real work to some other object. Each proxy method should, in the end, refer to a service object unless it is a subclass of a service. While this pattern isn’t a frequent guest in most Swift applications, it’s still very handy in some special cases. It’s irreplaceable when you want to add some additional behaviors to an object of some existing class without changing the client code.

Leave a Reply

Your email address will not be published. Required fields are marked *