You’ve got a big if/else statement to decide how to handle some logic in one of your classes.

if order.currency == 'gdp' && order.amount < 500
  PayPalPayment.process(order)
elsif order.currency == 'gdp' && order.amount > 500
  StripePayment.process(order)
elsif order.currency == 'usd'
  SquarePayment.process(order)
elsif order.currency == 'eur'
  PayPalPayment.process(order) 
elsif order.currency == 'zar'
  WesternUnionPayment.process(order)
elsif # more examples 
... 
end

Why’s this a problem?

The sender object (the class with the above code in) is completely coupled to the receiver classes (e.g. StripePayment , PayPalPayment etc…)— it knows all possible handlers and the logic that decides which handler to use. If the handler changes (e.g. one is removed, added or updated), or if the logic to determine which handler to use changes (e.g. Stripe introduces a limit) you risk breaking your application while making the change to this already bloated class, not to mention it’s increasingly difficult for someone to understand what you’re program is doing.

What problem does this design pattern solve?

  1. There are multiple objects that might handle the request (e.g. StripePaymentPayPalPayment) but you won’t know which one to use until runtime (i.e. when you know which currency is being used to make the purchase).
  2. You want to decouple the object making the request (the sender) and the object handling the request (the receiver) so that the sender only needs to know that the request will be handled, the receiver & sender have no explicit knowledge of each other.

What is the general concept of this design pattern?

The chain of responsibility pattern is a behavioural design pattern. Behavioural design patterns are concerned with algorithms and the assignment of responsibilities between objects including the patterns of communication between them. The other categories of design pattern are creational* and structural**.

This patterns avoids 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.


How can we implement this pattern?

Instead of a big if/else statement, we can create a chain of handlers. The request will go through each handler in order (each link in the chain passing it to the next if it cannot resolve the request) until it finds a handler that can resolve it.

Okay so let’s get into the code. We are going to create a base handler, that all handlers will inherit from

class BaseHandler   
  attr_reader :successor    

  def initialize(successor = nil)
    @successor = successor    
  end    
  def call(transaction)
    if can_handle?(transaction)
      handle(transaction)
    else
      successor.call(transaction)
    end
  end    
  def handle(_transaction)
    raise NotImplementedError, 'Each handler should respond to handle and can_handle? methods'   
  end 
end

Now we need to create the chain. We can start with the first handler, which we want to be the most specific handler.

#ruby #design-patterns #coding #learning-to-code #software-development #visual studio code

Design patterns in Ruby — chain of responsibility
1.45 GEEK