Design Patterns: Decorator in Swift – Unlocking the Power of Reusability

Design Patterns: Decorator in Swift – Unlocking the Power of Reusability

Before we dive into the design pattern of the decorator, let’s first understand what a design pattern is. In software engineering, a design pattern is a general, reusable solution to a commonly occurring problem within a given context. Design patterns provide developers with a blueprint for how to solve a particular problem, which can be applied to various scenarios.

Swift is a popular programming language used by many developers. It is a powerful language that is used to create apps for macOS, iOS, watchOS, and tvOS. Swift also provides developers with powerful features such as generics, tuples, and higher-order functions. In this article, we will explore the use of the decorator design pattern in Swift.

The decorator design pattern is a structural pattern that allows developers to add new functionality to an existing object without changing its structure. This pattern is often used when there is a need to extend the functionality of an existing class or when you need to add additional behavior to an existing class.

Let’s take a look at a simple example of the decorator pattern in Swift. Let’s say we have a class called Car that has two properties: color and speed. The Car class also has a method called drive() which makes the car move.

class Car {
  var color: String
  var speed: Int

  init(color: String, speed: Int) {
    self.color = color
    self.speed = speed
  }

  func drive() {
    print("Driving at \(speed) mph")
  }
}

Now let’s say we want to add a new feature to the Car class: the ability to accelerate. To do this, we can create a new class called AcceleratedCar that inherits from the Car class and adds the new feature.

class AcceleratedCar: Car {
  override func drive() {
    print("Accelerating at \(speed + 10) mph")
  }
}

The AcceleratedCar class extends the Car class by overriding the drive() method and adding the additional behavior of accelerating the car. However, this approach has several drawbacks. First, it requires us to create a new subclass for every new feature that we want to add. Second, it requires us to change the existing code of the Car class, which can lead to unexpected bugs.

This is where the decorator pattern comes in. With the decorator pattern, we can add new features to an existing class without having to modify the code of the existing class. To do this, we create a new class called CarDecorator that conforms to the Car protocol.

protocol Car {
  var color: String { get set }
  var speed: Int { get set }
  func drive()
}

class CarDecorator: Car {
  private let car: Car
  var color: String {
    get { return car.color }
    set { car.color = newValue }
  }
  var speed: Int {
    get { return car.speed }
    set { car.speed = newValue }
  }
  init(car: Car) {
    self.car = car
  }

  func drive() {
    car.drive()
  }
}

The CarDecorator class holds a reference to an instance of the Car class and implements the same methods and properties. This allows us to extend the functionality of the Car class without modifying the code of the existing class.

Now let’s create a subclass of the CarDecorator class called AcceleratedCarDecorator. This class will add the additional behavior of accelerating the car.

class AcceleratedCarDecorator: CarDecorator {
  override func drive() {
    print("Accelerating at \(speed + 10) mph")
  }
}

Now we can easily add the new feature of accelerating the car to the existing Car class without having to modify the existing code. All we need to do is create an instance of the AcceleratedCarDecorator and pass it an instance of the Car class.

let car = Car(color: "red", speed: 50)
let acceleratedCar = AcceleratedCarDecorator(car: car)
acceleratedCar.drive() // Output: Accelerating at 60 mph

The decorator pattern is a powerful tool for adding new features to existing classes without having to modify the existing code. By using this pattern, developers can easily extend the functionality of existing classes without having to create new subclasses. Furthermore, the decorator pattern allows developers to create more reusable code, as the same decorator can be used with multiple classes.

In conclusion, the decorator pattern is a powerful tool for extending the functionality of existing classes without having to modify the existing code. By using this pattern, developers can create more reusable code and easily add new features to existing classes.

Scroll to Top