Strategy and Decorator Design Patterns
Tags: designpatterns, decorator, strategy, ruby
Published: 2019-03-19 04:27:16

---
title: Strategy and Decorator Design Patterns
published: true
description: Description of Decorator and Strategy design patterns, implemented in Ruby
tags: Design Patterns, Decorator, Strategy, Ruby
---

# Why do I use a Decorator or Strategy?
Or any design pattern, for that matter? In general, design patterns are created and used to promote [object composition over inheritance](https://en.wikipedia.org/wiki/Composition_over_inheritance), allow for [(black-box) code reuse](https://stackoverflow.com/questions/98984/black-box-vs-white-box-reuse), better enforce the [single responsibility principle](https://en.wikipedia.org/wiki/Single_responsibility_principle), and reduce the size and unwieldiness of your code's classes in general.
Like any design pattern, Decorators and Strategies have specific scenarios when they are there are beneficial to use. These two patterns can have similar use cases, and it can be easy to confuse when you should use one or the other. According to [1], both Decorators and Strategies can be employed when your goal is an "alternative to extending functionality by subclassing". Strategies can also be used when you have classes with algorithmic dependencies, and Decorators can be used to easily alter the functionality of a class which itself is not easily changed.

So what actually are they and how do you use them?
Let's get specific. Decorators and Strategies are just extra classes I write to alter/extend the functionality of a class I have already written. The way they alter this functionality is different, and therefore they are useful in different scenarios. First, let's look at the class diagrams [1]:

#### Decorator

![Decorator Class Diagram](https://thepracticaldev.s3.amazonaws.com/i/q7flol9hz6ryy89ifxgw.png)


What is this saying? If you haven't looked at too many class diagrams, or you are only familiar with [dynamically typed languages](https://stackoverflow.com/questions/1517582/what-is-the-difference-between-statically-typed-and-dynamically-typed-languages), it can be confusing. Each box with a bold title represents a class. In Ruby, we won't actually be programming all of the classes we would in Java or C++, for example.

All of the boxes which do not say Concrete are the architecture of our inter-class APIs that we are designing. In statically typed languages, we have to define these in code as Interfaces, Prototypes, Abstract Classes, etc. depending on the language. In dynamically typed languages, they are defined in the documentation and in our minds as the engineers of the class ecosystem. There are ups and down to both statically and dynamically typed languages; statically typed classes error check for you, help you be more precise and cleaner in your code, and ensure you are designing your system correctly, while dynamically typed languages require less code and can be a lot simpler to create and read IF designed well and properly documented. If designed badly, they can be much harder to read and debug.
But now getting back to the `Decorator` Class Diagram; basically, this diagram tells us that we have a class `ConcreteComponent` and we want to extend its functionality. This class has the functions and properties as defined by `Component`. So, we make another class with the same API as `ConcreteComponent` (i.e. it conforms to the `Component` design) except that it has one extra reference: a `Component` (which is going to be the original class you wanted to extend the functionality of or any decorator it is already wearing), and we call this new design `Decorator`. We can make as many different types of `Decorator` classes, as long as it adheres to this design.

Above you can see that the `Component` can do an `Operation()`. So, our `Decorator` also has to be able to do an `Operation()`. Since our `Decorator` has a reference to `Component`, it just looks at how `Component` does `Operation()`, mimics that output, and then changes what it needs to and returns this new-and-improved output from its `Operation()` method. That is what the dotted lines are showing you above.

Pseudo-Code:

```
class NumberComponent
   func operation(x){
      return x
   }
end

class BinaryNumberDecorator
   constructor(component){
      this.c = component 
   }  
   func operation(x){
      return this.c.operation(x).toBinary()
   }
end

c = new NumberComponent()
d = new BinaryNumberDecorator(c)
x = 2
c.operation(x) // outputs what your original class returns
d.operation(x) // extends functionality of NumberComponent using the same function call
```

I'll show more complex, working ruby code below.

#### Strategy

![Strategy Class Diagram](https://thepracticaldev.s3.amazonaws.com/i/w7ai56qi1eilovnau2am.png)

Here, the `Context` is the class I want to extend the functionality of. So, I make a `Strategy` class that can perform that function. It is interchangeable because each `ConcreteStrategy` conforms to the same `Strategy` interface. Note that unlike the `Decorator`, the `Strategy` does not need to share an interface with `Context`. This design pattern is convenient when the functionality I want is complex and can be implemented with different algorithms. Let's say I am creating a class which needs to perform the [Fast Fourier Transform (FFT)](https://medium.com/@micah.shute/divide-and-conquer-the-fast-fourier-transform-f61cb060710b). Since the FFT can be calculated in different ways, and I may want to switch to a faster/better algorithm in the future, I can implement a Strategy to perform the calculation.

Pseudo-Code:

```
class DataContext
   constructor(data, fftStrategy = new Radix2Strategy()){
      this.data = data
      this.fftStrategy = fftStrategy
   }
   func fft(){
      return this.fftStrategy.fft(this.data)
   }
end

class BruteForceFFTStrategy
   func fft(data){
      ...perform brute force fft
      return calculated_fft
   }
end

class Radix2Strategy
   func fft(data){
      ...perform radix 2 strategy
      return calculated_fft
   }
end
```

#### Intuition

`Decorators` are kind of like Russian nesting dolls. You take an object you want and nest it inside of your class which uses the inner functionality and adds onto it to makes it more functional. So actually, `decorators` are more like in MIB when the little Arquillian is controlling the humanoid body inside the head. He is like the original `Component` and the body is like a `Decorator`. He could then decorate himself further by having his human decoration operate some sort of exoskeleton. At that point, the little alien and his exterior would have the same methods, like `moveArm()` or `push()`, but the decorated exoskeleton would have a much different output (i.e. he could push harder). As such, the `decorator` has to have the same interfaces as the underlying class. It eats the original `Component` and allows the world to interact with it the same way it would interact with the original `Component`.
Strategies, on the other hand, are kind of like replaceable cards in a robot. Imagine you pulled off the back plate and there were slots with digital cards inserted for each function such as eating, walking, talking, etc. You could take any of them out and replace them when an algorithm was updated or you wanted to change the behavior of the robot.
In general, if you are wondering whether to use a `Strategy` or `Decorator` design pattern, a rule of thumb is to keep the base class simple in a `decorator`. If the `Component` is too complicated, you will have to mirror too many methods in each `decorator`, and it will be better to use a `strategy`.
Also, decorators are widely used when you want to dynamically add functionality to an object, not necessarily an entire class (and perhaps withdraw this functionality at a later time). Strategies are commonly used to perform a function which is very complicated and can be performed in different ways (perhaps with different time/space complexities).
## Code Example
#### Decorators:

```ruby

class IceCream
 
    def initialize(price: 1.0)
        @price = price
    end
 
    def price=(amt)
        @price = amt
    end
 
    def price
        return @price
    end
 
    def ingredients
        "Ice Cream"
    end
 
end
 
 
class WithJimmies
    def initialize(item)
        @item = item
    end
    def price
        @item.price + 0.5
    end
 
    def ingredients
        @item.ingredients + ", Jimmies"
    end
end
 
class WithChocolateSyrup
    def initialize(item)
        @item = item
    end
   def price
        @item.price + 0.2
    end
 
    def ingredients
        @item.ingredients + ", Chocolate Syrup"
    end
end
 
class WithOreos
    def initialize(item)
        @item = item
    end
    def price
        @item.price + 1.0
    end
 
    def ingredients
        @item.ingredients + ", Oreos"
    end
end
 
 
class FroYo
 
    def initialize(price: 1.5)
        @price = price
    end
 
    def price=(amt)
        @price = amt
    end
 
    def price
        return @price
    end
 
    def ingredients
        "Froyo"
    end
end
 
 
treat = IceCream.new
treat = WithJimmies.new(treat)
treat = WithOreos.new(treat)
treat = WithChocolateSyrup.new(treat)
puts treat.ingredients # "Ice Cream, Jimmies, Oreos, Chocolate Syrup"
puts treat.price # 2.7
another_treat = FroYo.new
another_treat = WithJimmies.new(another_treat)
puts treat.ingredients # "Froyo, Jimmies"
# Froyo and Ice Cream (Components) and all of the Decorators have #price and #ingredients
# methods, making them conform to the same interface.
```

#### Strategies:


```ruby
class ChocolateSyrup
    def price
        0.2
    end 
    def ingredients
        "Chocolate Syrup"
    end
end
 
 
class Jimmies
    def price
        0.5
    end
    def ingredients
        "Jimmies"
    end
end
 
class Oreos
    def price
        1.0
    end
    def ingredients
        "Oreos"
    end
end
 
class IceCream
 
    attr_accessor :toppings, :price_strategy
 
    def initialize(toppings: , price_strategy: CalculatePriceStandardStrategy )
        @toppings = toppings
        @price_strategy = price_strategy.new
    end
 
    def price
        self.price_strategy.calculate(self.toppings)
    end
 
    def ingredients
        self.toppings.length > 0 ? "Ice Cream, " + self.toppings.map(&:ingredients).join(", ") : "Ice Cream"
    end

end

class CalculatePriceStandardStrategy
    def calculate(toppings)
        return 1.0 + toppings.reduce(0){ |cum, curr| cum + curr.price }
    end
end

class CalculatePriceRewardsMemberStrategy
    def calculate(toppings)
        return 0.5 + 0.8 * (toppings.reduce(0){ |cum, curr| cum + curr.price })
    end
end


toppings = [ChocolateSyrup.new, Jimmies.new, Oreos.new]
strategy = CalculatePriceStandardStrategy
treat = IceCream.new(toppings: toppings, price_strategy: strategy)
puts treat.ingredients # Ice Cream, Chocolate Syrup, Jimmies, Oreos
puts treat.price # 2.7
treat.price_strategy = CalculatePriceRewardsMemberStrategy.new
puts treat.price # 1.86
```



That covers the basics. You can see more in-depth descriptions and discussion in the reference below.


##### References:
[1] DESIGN PATTERNS Elements of Reusable Object-Oriented Software, Gamma, Helm, Johnson, Vlissides