  Strategy – Design Patterns in Swift

Introduction

The Strategy pattern enables selecting an algorithm at runtime. Instead of implementing a single algorithm directly, code receives run-time instructions as to which in a family of algorithms to use.

Use Strategy Pattern in Swift

The Context defines the interface of interest to clients. The Context maintains a reference to one of the Strategy objects. The Context does not know the concrete class of a strategy. It should work with all strategies via the Strategy interface.

Usually, the Context accepts a strategy through the constructor, but also provides a setter to change it at runtime. The Context allows replacing a Strategy object at runtime.

import XCTest

class Context {

private var strategy: Strategy

init(strategy: Strategy) {
self.strategy = strategy
}

func update(strategy: Strategy) {
self.strategy = strategy
}

print("Context: Sorting data using the strategy (not sure how it'll do it)\n")

let result = strategy.doAlgorithm(["a", "b", "c", "d", "e"])
print(result.joined(separator: ","))
}
}

The Context delegates some work to the Strategy object instead of implementing multiple versions of the algorithm on its own.

The Strategy interface declares operations common to all supported versions of some algorithm.

The Context uses this interface to call the algorithm defined by Concrete Strategies.

protocol Strategy {

func doAlgorithm<T: Comparable>(_ data: [T]) -> [T]
}

Concrete Strategies implement the algorithm while following the base Strategy interface. The interface makes them interchangeable in the Context.

class ConcreteStrategyA: Strategy {

func doAlgorithm<T: Comparable>(_ data: [T]) -> [T] {
return data.sorted()
}
}

class ConcreteStrategyB: Strategy {

func doAlgorithm<T: Comparable>(_ data: [T]) -> [T] {
return data.sorted(by: >)
}
}

Let’s see how it all works together.

class StrategyConceptual: XCTestCase {

func test() {

let context = Context(strategy: ConcreteStrategyA())
print("Client: Strategy is set to normal sorting.\n")