Components of the strategy pattern

The strategy pattern involves only a few components:

Let's attempt to generalize this implementation via protocols.

Strategy is the algorithm that runs the code, and that will be swapped at runtime. At a high level, a strategy is only dependent on its algorithm ReturnType:

protocol Strategy {
associatedtype ReturnType
func run() -> ReturnType
}

In practice, this abstraction lacks some definition, as we're missing some information about what we should pass to the algorithm. For the sake of our demonstration, let's rewrite the run() function with a single argument. As we're using generics, this argument can be anything we want:

protocol Strategy {
associatedtype ReturnType
associatedtype ArgumentType
func run(argument: ArgumentType) -> ReturnType
}

Now, for all the objects that need a different strategy, we can define a new Context type. This type will need to have an associated StrategyType, and keep a reference to the Strategy:

protocol Context {
associatedtype StrategyType: Strategy
var strategy: StrategyType { get set }
}

With the Context and Strategy protocols defined, we can jump into an example that showcases this design pattern.