“Software entities (classes, modules, methods) should be open for extension & closed for modification.”
This means that to make a class do new things you shouldn’t need to change the class itself. This makes your code more flexible & robust at the same time.
But how do you accomplish that?
Using design patterns like the strategy pattern ๐
Let’s say you have a ReportGenerator class, and you want to generate many kinds of report formats using the same data.
You could write a method for each report type, but that would mean you have to change the class (by adding a new method) every time you want to add a new type, breaking the open/close principle.
Or even worse!
You could have a single HUGE method with all sorts of if statements… These often don’t end up well.
But what if the class didn’t have to know how to format the reports?
What if the algorithm came from outside the class?
Then we can change the formatting algorithm whenever we want without changing the class itself.
This solves the problem.
And that’s exactly what the strategy pattern is all about.
Strategy Pattern Example
A strategy is implemented in the form of a class with a single method.
Here are some formatting strategies for the ReportGenerator class:
require 'json'
module ReportFormatters
class JSON
def self.format(data)
data.to_json
end
end
class PlainText
def self.format(data)
data.to_s
end
end
class HTML
def self.format(data)
html = ""
html << "
"
data.each { |product, amount| html << "
#{product}: #{amount}
" }
html << "
"
html
end
end
end
Notice how all of the strategies implement the format method. This method will be called by the report generator class.
Here is the code:
class ReportGenerator
def self.generate(data, formatter)
formatter.format(data)
end
end
data = { onions: 31, potatoes: 24, eggs: 10 }
p ReportGenerator.generate(data, ReportFormatters::HTML)
p ReportGenerator.generate(data, ReportFormatters::JSON)
p ReportGenerator.generate(data, ReportFormatters::PlainText)
Now:
If you want to change the output format (from HTML to PlainText) you just have to pass in a different strategy & it will work as long as the strategy implements the format method.
Another way to think about this pattern is that you are hiring a consultant specialized in a specific business strategy, the consultant will come in & implement the strategy for you, then this strategy will produce a specific result.
In contrast, a pattern like the decorator pattern is like adding new ornaments to a Christmas tree to make it more flashy.
You can only work with 1 strategy at a time, but you can have as many ornaments as you want.
Video
Summary
You have learned about the strategy design pattern, use it when you need to change part of what your class does without having to change the class itself.
Thanks for reading!
Don’t forget to share this post on Twitter if you found it interesting, it will help more people enjoy it too ๐
Thanks man, your description was very helpful! At last I was able to overcome laziness and grasp another pattern ๐ Now it feels a good portion of my code needs refactoringโฆ