Chapter 5: Strategy Pattern
大綱
When should you use it?
The strategy pattern defines a family of interchangeable objects that can be set or switched at runtime.
The object using a strategy.
This is most often a view controller when the pattern is used in iOS app development, but it can technically be any kind of object that needs interchangeable behavior.
The strategy protocol defines methods that every strategy must implement.
The strategies are objects that conform to the strategy protocol.

When should you use it?
Use the strategy pattern when you have two or more different behaviors that are interchangeableExcerpt .
Playground example
目標: an app that uses several “movie rating services” such as Rotten Tomatoes®, IMDb and Metacritic.
Instead of writing code for each of these services directly within a view controller, and likely having complex if-else statements therein, you can use the strategy pattern to simplify things by creating a protocol that defines a common API for every service.
The strategy protocol
public protocol MovieRatingStrategy {
var ratingServiceName: String { get }
func fetchRating(for movieTitle: String,
success: (_ rating: String, _ review: String) -> ())
}
The strategies
public class RottenTomatoesClient: MovieRatingStrategy {
public let ratingServiceName = "Rotten Tomatoes"
public func fetchRating(
for movieTitle: String,
success: (_ rating: String, _ review: String) -> ()) {
// In a real service, you'd make a network request...
// Here, we just provide dummy values...
let rating = "95%"
let review = "It rocked!"
success(rating, review)
}
}
public class IMDbClient: MovieRatingStrategy {
public let ratingServiceName = "IMDb"
public func fetchRating(
for movieTitle: String,
success: (_ rating: String, _ review: String) -> ()) {
let rating = "3 / 10"
let review = """
It was terrible! The audience was throwing rotten
tomatoes!
"""
success(rating, review)
}
}
The object
public class MoviewRatingViewController: UIViewController {
// MARK: - Properties
public var movieRatingClient: MovieRatingStrategy!
// MARK: - Outlets
@IBOutlet public var movieTitleTextField: UITextField!
@IBOutlet public var ratingServiceNameLabel: UILabel!
@IBOutlet public var ratingLabel: UILabel!
@IBOutlet public var reviewLabel: UILabel!
// MARK: - View Lifecycle
public override func viewDidLoad() {
super.viewDidLoad()
ratingServiceNameLabel.text =
movieRatingClient.ratingServiceName
}
// MARK: - Actions
@IBAction public func searchButtonPressed(sender: Any) {
guard let movieTitle = movieTitleTextField.text
else { return }
// The determination of which MovieRatingStrategy to use can be deferred until runtime, and this could even be selected by the user if your app allowed that.
movieRatingClient.fetchRating(for: movieTitle) {
(rating, review) in
self.ratingLabel.text = rating
self.reviewLabel.text = review
}
}
}
What should you be careful about?
Be careful about overusing this pattern. In particular, if a behavior won’t ever change, it’s okay to put this directly within the consuming view controller or object context.
The trick to this pattern is knowing when to pull out behaviors,
Tutorial project
Key points
The strategy pattern defines a family of interchangeable objects that can be set or switched at runtime.
This pattern has three parts: an object using a strategy, a strategy protocol, and a family of strategy objects.
The strategy pattern is similar to the delegation pattern: Both patterns use a protocol for flexibility. Unlike the delegation pattern, however, strategies are meant to be switched at runtime, whereas delegates are usually fixed.
Last updated
Was this helpful?