Greetings, traveler!
We continue to talk about Design Patterns. Next up is a behavioral design pattern, which is the Strategy. Strategy is a design pattern that defines a set of related algorithms and encapsulates them into their own objects. This allows the algorithms to be easily swapped out, making it easier to customize the app’s behavior.
Example of usage
There will be no delay, and we will analyze the example immediately. Imagine we have an audio streaming service that offers both free and premium options. The free version provides lower-quality audio, while the premium version offers a higher-quality listening experience. Users can choose between these two options based on their preferences and budget. If users want to enjoy premium audio, they can subscribe to the premium plan and enjoy the benefits of higher sound quality.
Let’s create an object — our User. It will have the isPremium property.
struct User {
var isPremium: Bool
}
Now, let’s create a class that will handle audio streaming. To start, we will implement it without using the Strategy Design Pattern.
final class RadioClient {
private let user: User
init(user: User) {
self.user = user
}
func streamAudio() {
if user.isPremium {
print("Streaming audio in high quality")
} else {
print("Streaming audio in low quality")
}
}
}
As we can see, the single responsibility principle is violated in this case. The class responsible for audio streaming must also determine whether a user is a premium subscriber and, depending on this information, broadcast audio of the appropriate quality to them.
Let’s see how we can improve our audio streaming class using the Strategy design pattern. First, we’ll define a StreamingStrategy protocol with a single function for streaming audio. This protocol will serve as the blueprint for our different audio streaming strategies.
protocol StreamingStrategy {
func streamAudio()
}
Then, let’s create two implementations of this protocol. One will be responsible for streaming audio at a lower quality, and the other will allow our premium users to enjoy the best possible quality of music.
final class DefaultStrategy: StreamingStrategy {
func streamAudio() {
print("Streaming audio in high quality")
}
}
final class PremiumStrategy: StreamingStrategy {
func streamAudio() {
print("Streaming audio in low quality")
}
}
The next step is to create a strategy property inside our audio streaming class. We will inject the value for this property during initialization. And now, we can simply rely on our strategy instead of trying to fit all the logic into a single function.
final class RadioClient {
private let strategy: StreamingStrategy
init(strategy: StreamingStrategy) {
self.strategy = strategy
}
func streamAudio() {
strategy.streamAudio()
}
}
Ready! We can use it.
let strategy = PremiumStrategy()
let radio = RadioClient(strategy: strategy)
radio.streamAudio()
Conclusion
We have just learned about a handy tool for encapsulating behavioral logic. The Strategy Design Pattern fits nicely into the principles of protocol-driven programming. Moreover, it allows you to change the type of algorithm behavior at runtime. This is a very efficient and elegant solution.
This concludes the discussion of this design pattern. In the following article, we will discuss the Template Method pattern.
Check out other posts in the Design Patterns series:
- Visitor Design Pattern in Swift
- Themplate Method Design Pattern in Swift
- State Design Pattern in Swift
- Observer Design Pattern in Swift
- Memento Design Pattern in Swift
- Mediator Design Pattern in Swift
- Iterator Design Pattern in Swift
- Command Design Pattern in Swift
- Chain of Responsibility Design Pattern in Swift
- Proxy Design Pattern in Swift
- FlyWeight Design Pattern in Swift
- Facade Design Pattern in Swift
- Decorator Design Pattern in Swift
- Composite Design Pattern in Swift
- Bridge Design Pattern in Swift
- Adapter Design Pattern in Swift
- Singleton Design Pattern in Swift
- Prototype Design Pattern in Swift
- Builder Design Pattern in Swift
- Abstract Factory Design Pattern in Swift
- Factory Method Design Pattern in Swift
- Design Patterns: Basics