Chain of responsibility design pattern in Ruby

Chain of responsibility design pattern

According to GoF and their great book “Design Patterns: Elements of Reusable Object-Oriented Software”, Chain of responsibility design pattern:

„Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.”

and it’s a part of an object behavioral design patterns.

A chain of responsibility is a design pattern that allows to decouple a sender of a request from its receiver by giving multiple object a chance to handle that request.

Instead of objects maintaining references to all receivers, they have only a single reference to their successor. From that perspective neither sender nor receivers has to know about chain’s structure.

Reduced coupling is one of the benefits of that design pattern. Another one is a flexibility in distribution of responsibility among objects. You can add or remove some responsibility by adding or removing objects from the chain. From the other hand, a consequence of that pattern is that receipt is not guaranteed. It may happen that any object from the chain will be able to handle the request.

The example

An example is worth more than thousand words, so let’s go through some code in Ruby. Let’s build a policy checker that will decide if a user (that can have a role assigned) has an access to a controller (for simplicity PORO). A controller should have corresponding policy class.

User class has a role.

Let’s define a few controllers as well.

That’s a main object here — Policy. It’s an interface/abstract class for handling requests.

All further more specific policies (receivers) will inherit from that class.

Let’s see how it works.

In an initializer we provide a successor which will be called (the request will be passed to) if current policy is not able to handle the request.

Main method here is check_access . It accepts two parameters: controller and user. As a result we will have an information if given user has an access to the controller. First we check if the policy is able to handle the request (by comparing request class with a class name of the policy without Policy — convention). If not, the request is passed to the successor if exists, if not, an exception is raised. If that’s a correct policy we invoke process_checking_access method that needs to be defined in every concrete class.

Based on a Policy class, let’s define a few concrete policies for our controllers.

The only thing that is changing is a definition of process_checking_access method that is different for every controller.

We can use our code in many ways. For example:

We build a user with admin role. Next we build a chain of policies. Finally, we run check_access on a first policy (LogsControllerPolicy). The request will be handled by it or passed to a next policy (ProfileControllerPolicy).

Want to know first about new articles from that blog?

Subscribe to my newsletter now! —

If you like this article and consider it useful for you, please support it with 👏.