format_list_bulletedState
Strategy is a behavioral design pattern that allows you to define a common algorithm and then put its implementations into separate classes.
Strategy pattern can sometimes be used interchangeably with the Template Method pattern. They often solve a similar problem in a different way.
Let’s assume that our application has an example table with users data.
| ID | NAME | EMAIL |
|----|-----------|--------------------|
| 1 | John Doe | john.doe@email.com |
|----|-----------|--------------------|
| 2 | Jane Doe | jane.doe@email.com |
We want to add functionality to it that will allow us to export it to files of various formats, e.g. HTML or TXT.
In the first step, we will define our main class, which will be responsible for export.
class Export
# Formatter will be used to define the implementation
attr_reader :data, :formatter
def initialize(data:, formatter:)
@data = data
@formatter = formatter.new(data)
end
# Method that export data in specific format
def call
formatter.call
end
end
Then we have to create a second class that will include specific implementation for a specific format. In this example JSON.
require 'json'
class JsonExport
attr_reader :data
def initialize(data)
@data = data
end
def call
create_file
format_data
add_data_to_file
save
end
private
def create_file
@file = File.new("./data.json", "w")
end
def format_data
@data = JSON.parse(data)
end
def add_data_to_file
file.write = data
end
def save
file.close
end
end
It’s quite similar to a Template Method, but now we don’t have to keep a strictly defined algorithm because each class can create its own unique implementation. So let’s create implementations for a plain text file.
class TxtExport
attr_reader :data
def initialize(data)
@data = data
end
def call
File.write('./data.txt', data.to_s)
end
end
Now if we prepare data from the table and run our code, we can easily generate code in both JSON and TXT formats.
users = [
{ id: 1, name: 'John Doe', email: 'john.doe@email.com' },
{ id: 2, name: 'Jane Doe', email: 'jane.doe@email.com' }
]
Export.new(data: users, formatter: JsonExport) # => Generate JSON file
Export.new(data: users, formatter: TxtExport) # => Generate TXT file
The whole power of this pattern is that we create a main class that is responsible for main action, and specific implementations of this action are passed to other classes.