# Ruby - Strategy Pattern

Hi, today we will continue learning new patterns (see also: decorator and template). This time we will go through very popular pattern - Strategy.

Wikipedia describes pattern this way:

The strategy pattern (also known as the policy pattern) is a software design pattern that enables an algorithm's behavior to be selected at runtime.

The strategy pattern:

• defines a family of algorithms,
• encapsulates each algorithm, and
• makes the algorithms interchangeable within that family.

That's too general description, so I suggest to go to examples straight away.

### Example #1

Let's create method which calculates net salary (salary you have after all taxes paid). Different countries have different rules for taxes, so code could look like this:

``````def net_salary(amount, country)
taxes = case country
when "Ukraine"
(amount * 0.05) + 313
when "U.S."
(amount * 0.2) + 100
when "Poland"
amount * 0.3
else
0
end

amount - taxes
end

net_salary(1000, "Poland")  # => 700.0
net_salary(1000, "Ukraine")  # => 637.0
``````

As we see from example - each country has own rules (strategies) of calculation. I've simplified logic of calculation, but actual implementation of each rule could contain a lot of code which would make `net_salary` method huge.

The main idea of Strategy pattern - to define set of objects (strategies) which solve the same problem in different way, depending on conditions. In our case they calculate amount of taxes differently, depending on selected country. All strategies should have the same interface to be interchangeable.

Let's rewrite example implementing strategy pattern:

``````class UkraineTaxes
def self.taxes(amount)
(amount * 0.05) + 313
end
end

class PolandTaxes
def self.taxes(amount)
amount * 0.3
end
end

class UsTaxes
def self.taxes(amount)
(amount * 0.2) + 100
end
end

class Taxes
def initialize
@strategies = {}
@strategies['Ukraine'] = UkraineTaxes
@strategies['Poland'] = PolandTaxes
@strategies['U.S.'] = UsTaxes
end

def net_salary(amount, country)
strategy = @strategies[country]

strategy ? amount - strategy.taxes(amount) : amount
end
end

Taxes.new.net_salary(1000, "U.S.") # => 700.0
``````

For each country we've created separate class which has method `.taxes`. Method `.taxes` contains all logic which calculates amount of taxes.

In `Taxes#initialize` we define a list of available strategies. Method `net_salary` dynamically selects proper strategy basing on `country` param. It will return `amount` If there is no applicable strategy.

Implementation of each strategy takes only one line of code, so we can avoid creating separate classes for that. We can use lambdas. That will make our code shorter:

``````class Taxes

def initialize(amount)
@amount = amount

@strategies = {}
@strategies['Ukraine'] = -> { (amount * 0.05) + 313 }
@strategies['Poland'] = -> { amount * 0.3 }
@strategies['U.S.'] = -> { (amount * 0.2) + 100 }
end

def net_salary(country)
strategy = @strategies[country]

strategy ? amount - strategy.call : amount
end

end

Taxes.new(1200).net_salary("U.S.") # => 700.0
``````

If you didn't use lambdas yet - don't worry. To simplify: lambdas are bits of code which we can assign to variables and execute them later (`strategy.call`). Also it's good to remember that lambdas execute width scope they've been defined.

This approach allows us to decouple implementation of each strategy from place where it might be used. Polymorphism helps us a lot here as well. Each strategy supports the same interface so we can call `strategy.call` even if we don't know which exact strategy will be executed.

I believe that simple examples allow us to develop skill of using patterns properly. Let's move forward and check another example.

### Example #2

In this example we receive data from external API and depending on response decide how to process it.

Response is an object which has methods `status` and `data`. `status` can be: `success`, `error` or `fail`. If status is `success` - we can use `response.data`. If returned `status` is `error` - we should display `response.error_message`. The `fail` status means that service is down and not responding at all.

``````def show
response = external_api.get(params[:id])

return handle_error if response.status == "error"
return handle_fail if response.status == "fail"

if response.status == "success"
"Successful response: #{response.data}"
end
end

def handle_error
puts "Error: #{response.error_message}"
end

def handle_fail
puts "Request Failed"
end
``````

I've simplified that code, but the problem is obvious. We have `response` object and should decide how to process it. In this example we do that using a lot of `if..else` statements which is not good. Imagine how much code we will get if each action will have all these `if's`.

It's a good place to use strategy pattern. We know that logic of processing should be extracted into classes or lambdas that have the same interface.

It's easy to decide which strategy to run because we have `response.status`. Let's implement that:

``````class ResponseHandler
def self.handle(response, strategies)
strategies[response.status.to_sym].call
end
end

def show
response = external_service.get(params[:id])

on_success = -> { "Successful response: #{response.data}" }
on_error = -> { "Error: #{response.error_message}" }
on_fail = -> { "Request Failed" }

ResponseHandler.handle(response, success: on_success, error: on_error, fail: on_fail)
end
``````

We did following steps:

1. Created class `ResponseHandler` which will handle responses from external API
2. Also, `ResponseHandler` accepts strategies which we want to run depending on status of response.
3. All strategies have the same interface and respond to `.call` method.
4. Having strategies with the same interface, `response` object and `ResponseHandler` class - we can easily run proper strategy: `strategies[response.status.to_sym].call`

I think that's a good code. `ResponseHandler` can be extended by default strategies, for example for `on_fail`. So we don't need to pass the same strategy for failed request every time.

If we have more complex logic - it will be easy to extract strategies into separate classes and get rid from lambdas. If classes support `.call` method - everything will work.

Also you see how easy to add new strategies. Just create new strategy class or lambda for corresponding response status and `ResponseHandler` will use that automatically. Which is good because it's an Open/Closed principle from SOLID.

If you see that your code contains a lot of `if..else` or `case..when`, check that code twice, there might be a chance that you're missing Strategy pattern there.

Cheers!