Observer Design Pattern in Ruby

model-view-controller architectural pattern. In a traditional MVC ( Model-View-Controller ) architecture, a model is a subject and a view is an observer. A view is notified when a model changes and responds accordingly. When the subject sends observers detailed information about what has changed, indiscriminately, this is known as the push model of the Observer pattern. When a subject sends only minimal information to its observers must ask for details explicitly, this is known as the pull model of the Observer pattern. Observer Design Pattern Ruby provides a simple mechanism to implement this design pattern using the Observable module. In this mechanism, the Notifier class uses the Observable module, which provides the methods for managing the associated observer objects. The observable object must:

  • assert that it has #changed
  • call #notify_observers
An observer subscribes to updates using #add_observer, which also specifies the method called via notify observers. The default method for notify observers is update.

Public Instance Methods

Instance methods are methods that are called on an instance of a class. We can use the below methods while using Observer instances.
  • add_observer(observer, func=:update)

Adds observer as an observer on this object, so that it will receive notifications.

  • changed(state=true)

Set the changed state of this object. Notifications will be sent only if the changed state is true.

  • changed?()

Returns true if this object’s state has been changed since the last notify_observers call.

  • count_observers()

Return the number of observers associated with this object.

  • delete_observer(observer)

Remove observer as an observer on this object so that it will no longer receive notifications.

  • delete_observers()

Remove all observers associated with this object.

  • notify_observers(*arg)
Notify observers of a change in state if this object’s changed state is true.

How it works

First, we have to create a basic structure of the Notifier class which will act as an Observer. The update() method is the callback that the Observable module will use when notifying changes to the observer, and the method name needs to be update(). Let’s take an example of an application which keeps track of the bike mileage and reminds us of when we need to take the vehicle in for a scheduled bike service.
require 'observer'
class Bike
  include Observable
  attr_reader :mileage,:service
  def initialize(mileage =0, service = 3000)
    @mileage,@service = mileage, service
    add_observer(Notifier.new)
  end
  def log(miles)
    @mileage += miles
    notify_observers(self, miles)
  end
end
Next, write the update method in Notifier class
class Notifier
  def update(bike, miles)
    puts "The bike has logged #{miles} miles, totaling #{bike.mileage} miles traveled."
    puts "The bike needs to be taken in for a service!" if bike.service <= bike.mileage
  end
end

By running the code we can see

bike = Bike.new(2300, 3000)
bike.log(100)
=> "The bike has logged 100 miles, totaling 2400 miles traveled."
bike.log(600)
=> "The bike has logged 300 miles, totaling 3000 miles traveled."
=> "The bike needs to be taken in for service!"

First, we create an instance of the Bike class with 2300 miles, and we set that it needs to be taken for service when it reaches 3000 miles.

I hope this example helps you understand ruby observer design pattern better.

Let me know in comments if you have any doubts or any implementation issues you have been facing recently. Thanks for reading!

References

]]>