Facade – Design Patterns in Swift

Introduction

The Facade design pattern can improve the readability and usability of a software library by masking interaction with more complex components behind a single (and often simplified) API, and provide a context-specific interface to more generic functionality (complete with context-specific input validation), and serve as a launching point for a broader refactor of monolithic or tightly-coupled systems in favor of more loosely-coupled code.

Facade Pattern – UML

Use Facade Pattern in Swift

The Facade class provides a simple interface to the complex logic of one or several subsystems. And it delegates the client requests to the appropriate objects within the subsystem. Moreover, it is also responsible for managing their lifecycle. All of this shields the client from the undesired complexity of the subsystem.

class Facade {

    private var subsystem1: Subsystem1
    private var subsystem2: Subsystem2

    init(subsystem1: Subsystem1 = Subsystem1(),
         subsystem2: Subsystem2 = Subsystem2()) {
        self.subsystem1 = subsystem1
        self.subsystem2 = subsystem2
    }

    func operation() -> String {

        var result = "Facade initializes subsystems:"
        result += " " + subsystem1.operation1()
        result += " " + subsystem2.operation1()
        result += "\n" + "Facade orders subsystems to perform the action:\n"
        result += " " + subsystem1.operationN()
        result += " " + subsystem2.operationZ()
        return result
    }
}

Depending on your application’s needs, you can provide the Facade with existing subsystem objects or force it to create them on its own. And its methods are convenient shortcuts to the sophisticated functionality of the subsystems. However, clients get only to a fraction of a subsystem’s capabilities.

In any case, to the Subsystem, the Facade is yet another client, and it’s not a part of the Subsystem. Therefore, The Subsystem can accept requests either from it or client directly.

class Subsystem1 {

    func operation1() -> String {
        return "Sybsystem1: Ready!\n"
    }

    func operationN() -> String {
        return "Sybsystem1: Go!\n"
    }
}

class Subsystem2 {

    func operation1() -> String {
        return "Sybsystem2: Get ready!\n"
    }

    func operationZ() -> String {
        return "Sybsystem2: Fire!\n"
    }
}

The client code works with complex subsystems through a simple interface provided by the Facade. When a facade manages the lifecycle of the subsystem, the client might not even know about the existence of the subsystem. This approach lets you keep the complexity under control.

class Client {

    static func clientCode(facade: Facade) {
        print(facade.operation())
    }
}

Let’s see how it all works together.

class FacadeConceptual: XCTestCase {

    func testFacadeConceptual() {

        let subsystem1 = Subsystem1()
        let subsystem2 = Subsystem2()
        let facade = Facade(subsystem1: subsystem1, subsystem2: subsystem2)
        Client.clientCode(facade: facade)
    }
}

The client code may have some of the subsystem’s objects already created.

Conclusion

In summary, Facade can be recognized in a class that has a simple interface, but delegates most of the work to other classes. Usually, facades manage the full life cycle of objects they use. Meanwhile, this pattern is commonly used in apps written in Swift. It’s especially handy when working with complex libraries and APIs.

Leave a Reply

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