Skip to main content

Swift Example

/// Strategy Design Pattern
///
/// Intent: Lets you define a family of algorithms, put each of them into a
/// separate class, and make their objects interchangeable.

import XCTest

/// The Context defines the interface of interest to clients.
class Context {

/// 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.
private var strategy: Strategy

/// Usually, the Context accepts a strategy through the constructor, but
/// also provides a setter to change it at runtime.
init(strategy: Strategy) {
self.strategy = strategy
}

/// Usually, the Context allows replacing a Strategy object at runtime.
func update(strategy: Strategy) {
self.strategy = strategy
}

/// The Context delegates some work to the Strategy object instead of
/// implementing multiple versions of the algorithm on its own.
func doSomeBusinessLogic() {
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 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() {

/// The client code picks a concrete strategy and passes it to the
/// context. The client should be aware of the differences between
/// strategies in order to make the right choice.

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

print("\nClient: Strategy is set to reverse sorting.\n")
context.update(strategy: ConcreteStrategyB())
context.doSomeBusinessLogic()
}
}
Client: Strategy is set to normal sorting.

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

a,b,c,d,e

Client: Strategy is set to reverse sorting.

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

e,d,c,b,a