Composition

Composition - similar to inheritance - is used to model relationships between multiple objects. Inheritance should be used if the relationship between objects can be represented as an is a relationship like “car is a vehicle”. Composition on the other hand should be used to model an has a relationship between multiple objects like “a car has a battery”.

One benefit of composition is that it allows you to reuse existing code. The key difference in reusing code via composition is that the reuse of code is referred to as black-boxed rather then as white-boxed reuse. Black-boxed reuse means that composed objects only have access to their interfaces, other characteristics like specific implementation details stay private.

Since objects that are composed together only know their interfaces, their connection is loosely coupled. This allows us to easily substitute an object which is very useful when writing unit tests for example.

Furthermore, we can keep each class encapsulated and focused on one task, which results in flat class hierarchies - so it will be less likely that you end up in an unmanageable state of a class which can happen with inheritance quite easily if you are not attentive.

A basic example of composition in Swift:

protocol EngineType {
    func start()
    func stop()
}

final class Engine: EngineType {

    // MARK: - Public Methods

    func start() {
        // starting the engine
    }

    func stop() {
        // stopping the engine
    }

}

final class Car {

    // MARK: - Properties

    private let engine: EngineType

    // MARK: - Initialization
    init(engine: EngineType) {
        self.engine = engine
    }

    // MARK: - Public Methods

    func setStart() {
        engine.start()
    }
    
}
Written on August 27, 2020