Mastering Swift's Development Blog

Follow Us On Twitter
  • Jon Hoffman

Strategy Pattern: Protocol Oriented Design Pattern

Updated: Sep 4


The Strategy pattern is a behavior design pattern where we encapsulate algorithms into single types. We are then able to use these types interchangeably which enables us to swap them out at runtime depending on our need. The strategy pattern is very similar to the command pattern. The difference is; with the command pattern we are swapping out types that change functionality while the strategy patter is swapping out types that perform the same function just in different ways.


Problem We Are Trying To Solve

In our applications, there are times where we need to separate the execution of an algorithm from the code that uses it. Usually this is when we have a type that needs to perform an action is several different ways, however which way to perform the action needs to be determined at runtime.


Our Solution

The Strategy pattern tells us that we should encapsulate the algorithms into types that adopt a specific protocol. We can then use instances of any of these types, using the interface defined by the protocol, to perform the specific actions. Using the interface defined by a protocol to interact with instances of different types, is called polymorphism.


The Example

In this example, we are writing a utility to compress files and providing several compression strategies including both zip and rar. The users will be able to select several files and then select the compression strategy to use. The following illustrates how the strategy pattern is used






As usual in our design pattern tutorials, we are going to be showing the minimal amount of code necessary to demonstrate this pattern because we want the focus of this post to be on how the strategy design pattern works and not on implementing the example.


As we do with most protocol-oriented design, we will start off with the protocol. This protocol defines the requirements for types that will perform the compression.

protocol CompressionStrategy {
    func compressFiles(filePaths: [String])
}

The CompressionStrategy protocol defines one function, which accepts an array of file paths as the only argument. For types that adopt this protocol, within this function is where they would perform the compression. Now let’s look at how we would use this protocol. We will create a type called FileCompression that will uses instances of types that adopt the CompressionStrategy protocol to compress a list of files. The follow shows an example of how this type could be created.

struct FileCompression {
    private var filePaths = [String]()
    
    mutating func addFilePath(_ filePath: String) {
        filePaths.append(filePath)
    }
    
    func compressFiles(compressionAlgorithm: CompressionStrategy) {

        //Code
           compressionAlgorithm.compressFiles(filePaths: filePaths)  
    }
}

We would use the addFilePath() function to build a list of files to compress and then use the compressFiles()function to compress them. The compressFiles() function accepts an instance of any type that adopts the CompressionStrategy protocol and will use that type to compress the files.


Now let’s build two types that will adopt the CompressionStrategy protocol that we can use with the compressFiles() function.

struct ZipCompression: CompressionStrategy {
    func compressFiles(filePaths: [String]) {
        // code for compression
    }
}

struct RarCompression: CompressionStrategy {
    func compressFiles(filePaths: [String]) {
        // code for compression
    }
}

The ZipCompression and RarCompression types both adopt the CompressionStrategy protocol and will implement the code necessary to compress the files. The following code shows how we would use these types with the FileCompression type to compress files.



var fileCompression = FileCompression()

fileCompression.addFilePath("File to add")
//add several more files

fileCompression.compressFiles(compressionAlgorithm: ZipCompression())


In this code, we create an instance of the FileCompression type and then added several files using the addFilePath() function. We then use the compressFiles() function, using a new instance of the ZipCompression type, to compress the files.


As we develop our compression utility, we would probably want to add additional compression types and by using the strategy pattern we can very easily add them by creating additional types that adopt the CompressionStrategy protocol.


This pattern is very useful when we need to swap out algorithms out at run time. This pattern, like the command pattern, gives us very flexible code that is easy to expand on in the future.



masteringSwift.jpeg

Mastering Swift 5.3

The sixth edition of this bestselling book, updated to cover through version 5.3 of the Swift programming language

Amazon

Packt

pop.jpeg

Protocol Oriented Programming

Embrace the Protocol-Oriented design paradigm, for better code maintainability and increased performance, with Swift.

Amazon

Packt