The Observable module is a useful and elegant way to watch for changes in an object in Ruby. A common example is for alerting of some condition within the object being observed. The example shown in the documentation is for a
Ticker class which has two observers: one for when the price goes below a certain level and one for when the price goes above a certain level. What we will do today is show something similar, but for a
CoffeeShop class instead. Let’s get to it!
So the application that we will build will be for a coffee shop where the manager has requested that they be notified when the shop is either full or empty. We will use the Observer pattern for this task!
To get this working we need to do three things:
Observablemodule into the
changedwhen a customer enters or departs the shop.
notify_observers, passing any usful paramaters, whenever a customer enters or exits the shop.
The basic class starts with including Observable and creating an initializer method that takes the name of our shop and the capacity - that is the maximum number of customers the shop can accomodate.
Now we need to create methods that allow a customer to enter and/or depart the shop. Notice that both methods call
changed, then adjust the customers array accordingly and finally calls
notify_observers on the Observable module.
Here is our first Observer. Note we pass in the instance of the class that we want the observer to observe (in this case our coffee shop instance). Then we call
add_observer passing in
self (that is the Observer class itself) - which essentially registers the observer with the object we are interested in.
Next note the
update method uses the instance of the coffee shop (@shop) and asks if it’s empty by calling a method we have not defined yet:
empty?. So then if the shop is indeed empty an appropriate alert will be sent to the manager.
Since its clear that we need a method on CoffeeShop to determine if it’s empty we can also define a method for if it’s full as well (so that we can use that in our next observer). Here are the method definitions for
full? on the
Next up we need to create the
CoffeeShopFullObserver class so that we can notify the manager to hire more staff! Here is how that looks:
Note how the constructor is exactly the same as the constructor in the
CoffeeShopEmptyObserver class. We can refactor this by creating an abstract CoffeeShopObserver class like so:
Then we can inherit our concrete observers (for empty or full states) with the new abstract
CoffeeShopObserver. See the link at the end of this post for the complete source code.
So lets get this application up and running and open up our coffee shop and let the customers in (and out!).
First we need to create an instance of our
CoffeeShop class and pass that onto both observers like so:
For basic usage we can manually assign some customers to enter or depart the shop like so:
The observer pattern as implemented in the Ruby Standard Library is pretty powerful and yet very easy to use. One can imagine using this in a real world application where instead of
puts one might send out an sms alert or an email to a real manager.
Here is a Gist containing the full source code with some extra stuff for randomly generating customers to come and go as they please thus producing a typical ebb and flow of activity in our cool coffee shop!