RubyGuides
Share this post!

How To Use The Decorator Pattern in Ruby

The decorator design pattern…

What is it, and how can you use this pattern in your Ruby projects?

The decorator design pattern helps you enhance an object by adding new capabilities to it without having to change the class.

Let’s have a look at an example.

Logging & Performance

In this example we are making HTTP requests using a gem like rest-client.

Here’s what that looks like:

require 'restclient'

data = RestClient.get("www.rubyguides.com")

Now:

Let’s say that we want to add logging to some of our requests, and we don’t want to change the RestClient module.

We can do this using the decorator pattern.

Here’s our logging module:

module LogHTTPRequest
  def get(url)
    puts "Sending Request For #{url}"
    super
  end
end

This will print the information we want on the screen then call the original get method from RestClient.

To add logging capabilities to a request you can use the extend method.

Like this:

class HTTPClient
  def initialize(client = RestClient)
    @client = client
  end

  def get(*args)
    @client.get(*args)
  end
end

client = HTTPClient.new
client.extend(LogHTTPRequest)

client.get("rubyguides.com")

You have to create this HTTPClient wrapper class because RestClient is a module & you can’t create objects from modules.

When To Use The Decorator Pattern

The beauty of this pattern is that you are only enhancing one object, so you could have a non-logging client & a logging client.

Another benefit is that you can layer these decorators & have one that does performance testing, another for logging, etc.

Combining decorators would not be possible if you used inheritance to create a HTTPClientWithLogging, and a HTTPClientWithPerformanceTesting class.

Inherithance Diagram

You can’t have WithLogging and WithPerformanceTesting at the same time unless you create this class…

class HTTPClientWithLoggingAndPerformanceTesting
  # ...
end

The decorator pattern solves this problem while avoiding code duplication & crazy class names.

Video

Summary

You have learned about the decorator design pattern, this pattern helps you add new capabilities to objects without having to change the class.

Don’t be passive! Now it’s your turn to practice & apply this concept yourself. It will help you remember this when you need it.

Share this article so more people can read it 🙂

2 comments
Sergey says 6 months ago

You need to remove self

module LogHTTPRequest
  def get(url)
    puts "Sending Request For #{url}"
    super
  end
end

    Jesus Castello says 6 months ago

    Yes, you are correct!

    I was testing a different version of this code & I forgot to remove the self 🙂

    Thank you.

Comments are closed