menu
Behavioralarrow_forward_ios
Observer
searchObserver

Description

A behavioral design pattern that aims to create a subscription method to notify multiple objects of events in an observed object.

Problem

Our app has several different subscription plans. Every time a User changes their subscription plan, we want to notify some company teams about that change.

Solution

Let’s create our user who will have a name and the type of subscription plan.

class User
  attr_reader :name, :plan

  def initialize(name:, plan:)
    @name = name
    @plan = plan
  end
end

john_doe = User.new(name: 'John Doe', plan: 'Standard')
And also create a Team class.

class Team
  attr_reader :name

  def initialize(name)
    @name = name
  end
end

finance = Team.new('Finance')
support = Team.new('Support')
To create an Observer pattern, we need to add several methods to the observed class to be able to manage it from the outside,

class User
  attr_reader :name, :plan, :observers

  def initialize(name:, plan:)
    @name = name
    @plan = plan
    @observers = [] # Store all observers in array
  end
  
  # After plan is changed we want to notify all observers
  def plan=(plan)
    @plan = plan
    
    notify_observers
  end
  
  # Adding observers
  def add_observer(observer)
    @observers << observer
  end
  
  # Removing observers
  def delete_observer(observer)
    @observers.delete(observer)
  end

  # All observers from the list will be updated
  def notify_observers
    @observers.each { |observer| observer.update(self) }
  end
end
And of course we need to provide update method that do something after notification.

class Team
  attr_reader :name

  def initialize(name)
    @name = name
  end

  def update(user)
    # Increase the amount, provide additional services,
    # or do something else... 
  end
end
Now if we add observers to the User, after plan is changed all observer will be notified.

john_doe.add_observer(finance)
john_doe.add_observer(support)

# After plan is changed, Team update method will be triggered
john_doe.plan = 'Premium'
If you want to use this pattern in Ruby you don’t have to create it from scratch because you can use it from the standard library.