You are here:   ArielOrtiz.info > S/W Design and Architecture > Observer Pattern

Observer Pattern

Objectives

During this activity:

This activity helps students develop the following skills, values and attitudes: ability to analyze and synthesize, capacity for identifying and solving problems, and efficient use of computer systems.

Activity Description

This activity can be developed individually or in pairs.

  1. Create a folder called observer. Inside this folder, create two files called: weather.rb and weather_test.rb.

    Both Ruby source files must start with a comment containing title, date, and the authors' personal information. For example:

    # Observer Pattern
    # Date: 03-Sep-2015
    # Authors:
    #          A00456654 Thursday Rubinstein 
    #          A01160611 Anthony Stark
    
  2. You are required to build a weather data monitoring system using the Observer pattern (this example was taken from [FREEMAN] pp. 37-60). In the weather.rb source file, define four classes:

    • WeatherData: This is the subject of our Observer pattern implementation. Include as a mixin the Observable module and add to it a set_measurements method, which takes three parameters: temperature, humidity, and pressure. This method must notify all its observing objects that a change has occurred. This means that the update method for every observer must be indirectly called with the three previously mentioned parameters. Check chapter 5 of [OLSEN] and the Observable documentation.
    • CurrentConditionsDisplay: An observer that displays to the standard output the current weather conditions.
    • StatisticsDisplay: An observer that displays to the standard output weather statistics (average, maximum and minimum temperatures so far).
    • ForecastDisplay: An observer that displays to the standard output a weather forecast. If the current pressure is higher than the previous pressure, it predicts an improvement on the weather. If the current pressure is lower than the previous pressure, it predicts a cooler, rainy weather. Otherwise, it predicts that the weather will stay the same. You may assume that the previous pressure is equal to zero when this observer is updated for the very first time.

    Check the unit tests in the following step to see the expected display formats for each of the observers.

  3. Make sure the code that you write behaves exactly as expected by the following unit tests.

    # File: weather_test.rb
    
    require 'minitest/autorun'
    require 'stringio'
    require 'weather'
    
    # If you get a NameError saying that Minitest is an 
    # uninitialized constant, replace Minitest::Test with
    # MiniTest::Unit::TestCase
    class WeatherTest < Minitest::Test
    
      def setup
        @out = StringIO.new
        @old_stdout = $stdout
        $stdout = @out
        @weather_data = WeatherData.new
      end
    
      def teardown
        $stdout = @old_stdout
      end
    
      def do_set_measurements
        @weather_data.set_measurements(80.0, 65.0, 30.4)
        @weather_data.set_measurements(82.0, 70.0, 29.2)
        @weather_data.set_measurements(78.0, 90.0, 29.2)
      end
    
      def test_current_conditions_display
        current_display = CurrentConditionsDisplay.new
        @weather_data.add_observer(current_display)
        do_set_measurements
        assert_equal "Current conditions: 80.0°F and 65.0% humidity\n"  \
                     "Current conditions: 82.0°F and 70.0% humidity\n"  \
                     "Current conditions: 78.0°F and 90.0% humidity\n", \
                     @out.string
      end
    
      def test_statistics_display
        statistics_display = StatisticsDisplay.new
        @weather_data.add_observer(statistics_display)
        do_set_measurements
        assert_equal "Avg/Max/Min temperature = 80.0/80.0/80.0\n"  \
                     "Avg/Max/Min temperature = 81.0/82.0/80.0\n"  \
                     "Avg/Max/Min temperature = 80.0/82.0/78.0\n", \
                     @out.string
      end
    
      def test_forecast_display
        forecast_display = ForecastDisplay.new
        @weather_data.add_observer(forecast_display)
        do_set_measurements
        assert_equal "Forecast: Improving weather on the way!\n"       \
                     "Forecast: Watch out for cooler, rainy weather\n" \
                     "Forecast: More of the same\n",                   \
                     @out.string
      end
    
      def test_all_together
        current_display = CurrentConditionsDisplay.new
        statistics_display = StatisticsDisplay.new
        forecast_display = ForecastDisplay.new
        @weather_data.add_observer(current_display)
        @weather_data.add_observer(statistics_display)
        @weather_data.add_observer(forecast_display)
        do_set_measurements
        assert_equal "Current conditions: 80.0°F and 65.0% humidity\n" \
                     "Avg/Max/Min temperature = 80.0/80.0/80.0\n"      \
                     "Forecast: Improving weather on the way!\n"       \
                     "Current conditions: 82.0°F and 70.0% humidity\n" \
                     "Avg/Max/Min temperature = 81.0/82.0/80.0\n"      \
                     "Forecast: Watch out for cooler, rainy weather\n" \
                     "Current conditions: 78.0°F and 90.0% humidity\n" \
                     "Avg/Max/Min temperature = 80.0/82.0/78.0\n"      \
                     "Forecast: More of the same\n",                   \
                     @out.string
      end
    
    end
    

Deliverables

Create a compressed tarball file with the full contents of the observer directory. Call this file observer.tgz. From a terminal, you can use the following command to create this file (make sure to run it at the same level where the observer folder resides):

tar czf observer.tgz observer

✔ Upload Instructions

To deliver the observer.tgz file, please provide the following information:

Request PIN

Due date is Thursday, September 3.