Composite Design Pattern in Swift


Greetings, traveler!

The Composite Design Pattern is a Structural Design Pattern. It is a practical tool for composing objects into tree structures. This means you can work with these structures as if they were individual objects, making your code more flexible and easier to manage. It’s like having a tree structure where each element represents a unique object or a collection of objects, all sharing the same interface.

Example of usage

Let’s imagine that we own a fast-food restaurant and have added a new item to our menu — a set of burgers. Our set includes a hamburger, chicken, and veggie burger. These burgers differ in their composition, with different sauces and patties. To prepare each burger, we add a sauce and a patty corresponding to the chosen burger.

protocol BurgerProtocol {
    func addPatty()
    func addSause()
    func pack()
}

extension BurgerProtocol {
    func pack() {
        print("The \(String(describing: self)) is packed")
    }
}

struct Hamburger: BurgerProtocol {

    func addPatty() {
        print("Beef Patty")
    }
    
    func addSause() {
        print("Ketchup")
    }
    
}

struct VeggieBurger: BurgerProtocol {

    func addPatty() {
        print("Vegetable Patty")
    }
    
    func addSause() {
        print("Mayo")
    }
    
}

struct ChickenBurger: BurgerProtocol {

    func addPatty() {
        print("Chicken Patty")
    }
    
    func addSause() {
        print("Mayo + Ketchup")
    }
    
}

By using the Composite design pattern, we can streamline our operations. Instead of dealing with each burger separately, we can create a composite with an identical interface and assign it the responsibility of preparing the entire set. This saves us time and makes our code more efficient and easier to maintain.

final class BurgerSetComposite: BurgerProtocol {
    
    private let setItems: [FastFoodProtocol] = [
        Hamburger(),
        VeggieBurger(),
        ChickenBurger()
    ]
    
    func addPatty() {
        setItems.forEach {
            $0.addPatty()
        }
    }
    
    func addSause() {
        setItems.forEach {
            $0.addSause()
        }
    }
    
    func pack() {
        setItems.forEach {
            $0.pack()
        }
    }
    
}

let composite = BurgerSetComposite()
composite.addPatty()
composite.addSause()
composite.pack()

Looks good!

Conclusion

The Composite Design Pattern is widely used due to its simplicity. It helps us to create a unified interface for working with multiple components, making it easier to manage and maintain. I hope you found this article helpful. In the following article, we will discuss the Decorator Design Pattern. See you there!