Overview
The observer pattern is a software design pattern in which an object, called the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods. It is mainly used to implement distributed event handling systems. The Observer pattern is also a key part in the familiar model–view–controller (MVC) architectural pattern.[1] The observer pattern is implemented in numerous programming libraries and systems, including almost all GUI toolkits.
Problems Observer Pattern Solves:
- Think about a spreadsheet, where editing the contents of one cell not only changes the number in the grid but also changes the column totals, alters the height of one of the bars in a bar chart, and enables the Save button
- a personnel system that needs to let the payroll department know when someone’s salary changes.How can you make the Employee object spread the news about salary changes without tangling it up with the payroll system?
Solving Employee Salary problem with simple technique
class Employee attr_reader :name, :title attr_reader :salary def initialize(name, title, salary, payroll) @name = name @title = title @salary = salary @payroll = payroll end def salary=(new_salary) @salary = new_salary @payroll.update(self) end end
Payroll class be like
class Payroll def update(changed_employee) puts("Cut a new check for #{changed_employee.name}!") puts("His salary is now #{changed_employee.salary}!") end end
We can now change Fred’s wages:
payroll = Payroll.new fred = Employee.new('Fred', 'Crane Operator', 30000, payroll) fred.salary = 35000
And the payroll department will know all about it:
Cut a new check for Fred!
His salary is now 35000!
Problem with this solution:
The trouble with this code is that it is hard-wired to inform the payroll department about salary changes.
- What do we do if we need to keep other objects—perhaps some accounting-related classes—informed about Fred’s financial state?
- As the code stands right now, we must go back in and modify the Employee class.
A Better way to do that : Using Observer Pattern
class Employee def initialize(name, title, salary) @name = name @title = title @salary = salary @observers = [] end def salary=(new_salary) @salary = new_salary notify_observers end def notify_observers @observers.each do |observer| observer.update(self) end end def add_observer(observer) @observers << observer end def delete_observer(observer) @observers.delete(observer) end end
Now any object that is interested in hearing about changes in Fred’s salary can simply register as an observer on Fred’s Employee object:
fred = Employee.new('Fred', 'Crane Operator', 30000.0) payroll = Payroll.new fred.add_observer( payroll ) fred.salary = 35000.0 # output Cut a new check for Fred! His salary is now 80000.0!
By building this general mechanism, we have removed the implicit coupling between the Employee class and the Payroll object.
- Employee no longer cares which or how many other objects are interested in knowing about salary changes;
- it just forwards the news to any object that said that it was interested.
- In addition, instances of the Employee class will be happy with no observers, one, or several embedded hard-wired inside it:
class TaxMan def update(changed_employee) puts("Send #{changed_employee.name} a new tax bill!") end end tax_man = TaxMan.new fred.add_observer(tax_man) # Suppose we change Fred’s salary again: fred.salary = 90000.0
Now both the payroll department and the tax man will hear about it:
# Output
Cut a new check for Fred!
His salary is now 80000.0!
Send Fred a new tax bill!
Conclusion:
The GoF called this idea of building a clean interface between the source of the news that some object has changed and the consumers of that news the Observer pattern (Figure 5-1).
- The GoF called the class with the news the subject class. In our example, the subject is the Employee class.
- The observers are the objects that are interested in getting the news.
- In our employee example, we have two observers: Payroll and TaxMan.
- When an object is interested in being informed of the state of the subject, it registers as an observer on that subject.
This document contains just the Introduction to Observer Pattern: You can explore more and update/extend this document further
References:
Book: Design Patterns in Ruby – Russ Olsen
One thought on “GOF [Gang of Four] : Observer Design pattern in Ruby”