© James E. McDonough 2017

James E. McDonough, Object-Oriented Design with ABAP, 10.1007/978-1-4842-2838-8_13

13. Observer Design Pattern

James E. McDonough

(1)Pennington, New Jersey, USA

The next stop on our voyage through the Design Patterns galaxy takes us to the Observer design pattern, another of the design patterns found in the GoF catalog. We will find this design pattern useful in situations where one class needs to be kept aware of changes occurring in another class.

The Observer design pattern often is described as a publish and subscribe arrangement between entities. A good example of this is the process of getting a daily newspaper delivered to you. You, as the customer, subscribe to the newspaper. The newspaper publishes a new edition every day. Since you are a subscribing customer, a copy is delivered to you every day. Copies also are delivered to all of the other subscribers. After a while you decide you no longer want to receive this newspaper, so you cancel your subscription. The newspaper continues to be published daily, but you no longer get a copy delivered to you.

To further explain the Observer design pattern, I’ll start with a business scenario, introduce a new business requirement, and then show how the Observer design pattern addresses the new requirement.

Transportation Business Scenario

In the early 1980s I spent 15 months as a driver for Carretta Trucking, Incorporated of Paramus, New Jersey, which specialized in hauling produce from the west coast to the east coast of the United States using trucks with a team of two drivers, where one would drive while the other slept. This was a 24-hours-per-day, 365-days-per-year operation. The company maintained two dispatch centers: one on the east coast in Paramus, New Jersey and one on the west coast in Brea, California. At any given time, there were some trucks headed west, some headed east, and some that had already delivered the westbound load but had not yet loaded with an eastbound load.

My co-driver Ed and I eventually settled into a comfortable routine where each of us would drive for a full 10-hour shift1 followed by a 2-hour stop for food, fuel, and relaxation before changing drivers. We usually found ourselves stopping between the hours of 10:00 and 12:00. We could average about 50 miles per hour when moving2 and usually we were able to complete a combined 20 hours of driving in a 24-hour period, meaning that a 3,000 mile trip from coast to coast would take about 72 hours.

Ed and I made many runs to the west coast and back over the months we spent together as a team. A typical run for us is described in Table 13-1, which shows us hauling a load of cosmetics leaving Hillside, New Jersey at 4:00 p.m. Friday, January 8, 1982, and, 67 hours later, delivering it to Los Angeles California at 11:00 a.m. Monday, January 11, 1982, and then heading empty to Salinas, California to pick up a load of lettuce leaving at 6:30 p.m., and, 72 hours later, delivering it to Bronx, New York at 6:30 p.m. Thursday, January 14, 1982, with all times shown using Eastern Standard Time.

Table 13-1. Round-Trip Hauling Freight Between the East Coast and West Coast of the United States

Tractor: 440

Trailer: R227

Location

Arrive

Depart

Miles to destination

Miles between

stops

Pulp Temp

Start date:

01/08/1982

Load id:cosmetics

Co-drivers:

E. Kading

J. McDonough

Hillside, New Jersey

2:45 p.m. Fri

4:00 p.m. Fri

2890

  
    

297

 

Toms Brook, Virginia

10:00 p.m. Fri

12:00mid Fri

2593

  
    

503

 

Cookeville, Tennessee

10:00 a.m. Sat

12:00m Sat

2090

  
    

495

 

Russellville, Arkansas

10:00 p.m. Sat

12:00mid Sat

1595

  
    

522

 

Amarillo, Texas

10:00 a.m. Sun

12:00m Sun

1073

  
    

518

 

Holbrook, Arizona

10:00 p.m. Sun

12:00mid Sun

555

  
    

555

 

Los Angeles, California

11:00 a.m. Mon

 

0

  

Start date:

01/11/1982

Load id:empty

Co-drivers:

E. Kading

J. McDonough

Los Angeles, California

 

11:30 a.m. Mon

303

  
    

303

 

Salinas, California

6:00 p.m. Mon

 

0

  

Start date:

01/11/1982

Load id:

lettuce

Co-drivers:

E. Kading

J. McDonough

Salinas, California

 

6:30 p.m. Mon

3009

 

34°F

    

175

 

West Sacramento, California

10:00 p.m. Mon

12:00mid Mon

2834

 

34°F

    

527

 

West Wendover, Nevada

10:00 a.m. Tue

12:00m Tue

2307

 

33°F

    

511

 

Laramie, Wyoming

10:00 p.m. Tue

12:00mid Tue

1796

 

33°F

    

491

 

Lincoln, Nebraska

10:00 a.m. Wed

12:00m Wed

1305

 

34°F

    

495

 

Joliet, Illinois

10:00 p.m. Wed

12:00mid Wed

810

 

34°F

    

500

 

Brookville, Pennsylvania

10:00 a.m. Thu

12:00m Thu

310

 

34°F

    

310

 

Bronx, New York

6:30 p.m. Thu

 

0

 

34°F

Each morning between 8:00 a.m. and noon, east coast time, we were required to call the dispatcher on the coast to which we were heading, state our location and, if eastbound, the pulp temperature of the produce we were hauling.

I left the company in June, 1982 just as they were about to install a computerized system to enable better tracking of their trucks.3

New Business Requirement4

The dispatchers complained to company management that although the new computers enabled better managing and tracking of the trucks, they had up-to-date information about the location of the trucks only at the moment the drivers made their daily morning call. As the day progressed, the dispatchers were uncertain whether the trucks were moving at all, and if so, whether they still were moving at the expected 50 miles per hour average. They felt the new computerized tracking was not much better than the old manual methods they used prior to the new computer system. They prevailed upon management to improve the computer system so the information on individual trucks was closer to real-time.

After agreeing to improve the computer system, management contacted the computer services company responsible for the software maintenance and explained the challenge. The developers devised a way to eliminate the need for drivers to call dispatchers, and instead had the drivers, via on-board communication links, simply log into the system anytime they stopped for an extended break, indicating they were no longer moving and giving their location, and again just before getting underway, indicating they had begun moving once again.

This enabled the dispatchers to approximate real-time information about the trucks, allowing them to determine at any hour of the day or night the location of each truck. They always knew which trucks were stopped and where they were located. The location of the moving trucks could now be estimated by multiplying the number of hours since the time the truck last got underway by the average speed of 50 miles per hour.5

Under Observation

The Observer design pattern is one where instances of classes observe changes in instances of other classes and take action based on the change. Observer is categorized by GoF with a behavioral purpose and an object scope. The intent behind this design pattern is the following:

  • Defines a one-to-many dependency between objects so that when one object changes state , all of its dependents are notified and updated automatically. 6

Observer makes use of these participants7 working in collaboration with each other:

  1. Subject : Knows its observers. Any number of Observer objects many observe a subject. Provides an interface for attaching and detaching Observer objects.

  2. Observer: Defines an updating interface for objects that should be notified of changes in a subject.

  3. ConcreteSubject: Stores state of interest to ConcreteObserver objects. Sends a notification to its observers when its state changes.

  4. ConcreteObserver: Maintains a reference to a ConcreteSubject object. Stores state that should stay consistent with the subject’s. Implements the Observer updating interface to keep its state consistent with the subject’s.

The UML class diagram for Observer is shown in Figure 13-1.

A447555_1_En_13_Fig1_HTML.jpg
Figure 13-1. UML class diagram for the Observer design pattern

The concrete observer is an instance of a class that needs to be aware of changes taking place in an instance of another class. The concrete subject is an instance of a class to which the concrete observer needs to be aware of changes.

The concrete observer implements the Observer interface. This means it needs to provide an implementation for the update method.

The concrete subject implements the Subject interface. This means it needs to provide implementations for methods registerObserver, removeObserver, and notifyObserver.

During execution, the concrete observer invokes the registerObserver method of the concrete subject, effectively indicating to the concrete subject that it wants to be made aware of its changes. The concrete subject retains the address of the concrete observer. This constitutes a “has a” relationship between the concrete subject and the concrete observer; the concrete subject “has a” concrete observer. Indeed, the concrete subject may have zero to unlimited concrete observers, and the address of each one will be retained in a list of observers.

When the subject changes its state , it invokes its own notifyObservers method. The processing here is to loop through the list of addresses for concrete observers, and for each one invoke its update method. The concrete subject does not need to know anything about the type of class the concrete observer is; it merely relies on the fact that the concrete subject implements the Observer interface, which means the concrete subject must provide an implementation for the update method.

When the concrete observer no longer needs to be aware of changes in the subject, it invokes method removeObserver of the subject, which will cause the address of the observer to be removed from the list of observers.

The relationship between a concrete observer and a concrete subject is one of loose coupling. The communication between these two objects occurs at the level of the interface defined by the subject and observer entities. Accordingly, there is no direct communication between either concrete class; each one invokes the methods of the other via its respective public interface. It also illustrates another example of class composition, since a concrete subject has a list of concrete observers to be notified when its state changes.

Let’s see how this applies to a business scenario.

Practical Observations

Upon starting the enhanced computer system for Carretta Trucking, two instances of a dispatcher class are created: one for the east coast dispatcher and one for the west coast dispatcher. Also, there are multiple instances of the truck class to represent the various trucks carrying their loads. One of them is an instance of a truck to represent the one Ed and I are driving: tractor 440 and trailer R227.

Upon being notified that truck 440 is on its way to pick up a westbound load, the west coast dispatcher issues a command causing the corresponding west coast dispatcher instance to invoke the registerObserver method for truck instance 440, the one Ed and I are driving. The implementation of the registerObserver method by the truck class simply places the address of the requesting observer class into its list of observers. Accordingly, the instance representing truck 440 now has the address of the west coast dispatcher as an entry in its list of observers.

Follow along using Table 13-1 as Ed and I drive truck 440 from the east coast to the west coast and back again.

  • Upon arriving in Hillside, NJ at 2:45 p.m. Friday, we log into the system and issue a command indicating we have stopped, which causes our truck instance to change state; we are no longer moving. This command causes our truck instance to invoke its notifyObservers method, which calls the update method for each of its observers. The update method implemented in the dispatcher class simply records the date, time, and the new location of our truck. At this point, our truck has only one observer, the west coast dispatcher, and the corresponding instance of the west coast dispatcher, upon being so notified by having its update method invoked, records that we have stopped in Hillside, New Jersey at 2:45pm Friday.

  • At 4:00 p.m. Friday Ed and I are loaded and ready to get underway. We log into the system and issue a command indicating we have started, causing our truck instance again to change state : we are now moving. This command causes our truck instance to invoke its notifyObservers method again and calls the update method for each of its observers. Our truck still has only one observer, and the corresponding instance of the west coast dispatcher, upon being so notified, records that we have started.

  • At 10:00 p.m. Friday we arrive in Toms Brook, Virginia. We log into the system and issue a command indicating we have stopped. Again, this command causes our truck instance to invoke its notifyObservers method. We still have only one observer and its corresponding instance is notified that we have stopped in Toms Brook, Virginia.

  • At midnight Friday we change drivers and are ready to get underway again. Once more we log into the system and issue a command indicating we have started, which again causes our truck instance to invoke its notifyObservers method, which again notifies the west coast dispatcher instance that we have started.

  • At 10:00 a.m. Saturday we arrive in Cookeville, Tennessee and depart 2 hours later. We logged onto the system with each change of status, stopping and then starting again, and each time our truck instance invoked its notifyObservers method to update the west coast dispatcher with our location and state.

  • At 10:00 p.m. Saturday we arrive in Russellville, Arkansas and depart 2 hours later. We follow the same process we did 12 hours earlier.

By this time, we have been westbound for 32 hours. We logged onto the system each time we started and stopped, so the west coast dispatcher was notified with each change in our status.

At 8:00am Sunday morning the west coast dispatcher checks to see where Ed and I are located. The last notification our truck instance gave to the west coast dispatcher instance was 8 hours earlier when we indicated we were departing Russellville, Arkansas. Upon seeing this information, the west coast dispatcher can extrapolate that we are still moving and, based on our approximate rate of 50 miles per hour when moving, are located about 400 miles west of Russellville, Arkansas, which would put us in the vicinity of Sayre, Oklahoma.

  • At 10:00 a.m. Sunday we arrive in Amarillo, Texas and depart 2 hours later. With each change, our truck instance invokes its notifyObservers method to update the west coast dispatcher instance accordingly.

  • At 10:00 p.m. Sunday we arrive in Holbrook, Arizona and depart 2 hours later. Again, we follow the same process we did 12 hours earlier.

  • At 11:00 a.m. Monday we arrive in Los Angeles, California where we stop and unload.8 Upon logging onto the system to issue the command indicating we have stopped, our truck instance invokes its notifyObservers method to update the west coast dispatcher instance with the location where we have stopped.

After our cargo has been unloaded, we notify the west coast dispatcher, who sends us 300 miles north to Salinas, California to pick up an eastbound load of lettuce.

At this point, the west coast dispatcher no longer has any interest in being an observer of our truck, so it issues a command causing the west coast dispatcher instance to invoke the removeObserver method of our truck instance. The implementation of the removeObserver method by the truck class simply discards the address of the requesting observer class from its list of observers. Accordingly, the instance of our truck now has no addresses in its list of observers.

Meanwhile, the east coast dispatcher is now interested in being an observer to our truck. Similarly, the east coast dispatcher issues a command causing the corresponding east coast dispatcher instance to invoke the registerObserver method for the instance of the truck we are driving. Accordingly, the instance of our truck now has the address of the east coast dispatcher in its list of observers.

  • At 6:00 p.m. Monday we arrive in Salinas, California, and, following the same process, our truck instance invokes its notifyObservers method to update the east coast dispatcher instance that we have stopped here.

  • At 6:30 p.m. Monday we depart Salinas, and our truck instance invokes its notifyObservers method to update the east coast dispatcher instance that we have started.

  • At 10:00 p.m. Monday we arrive in West Sacramento, California and depart 2 hours later. With each change, our truck instance invokes its notifyObservers method to update the east coast dispatcher instance accordingly, including our pulp temperature of 34°F.

  • At 10:00 a.m. Tuesday we arrive in West Wendover, Nevada and depart 2 hours later. With each change, our truck instance invokes its notifyObservers method to update the east coast dispatcher instance accordingly, including our pulp temperature of 33°F

This process continues as we change drivers again

  • between 10:00 p.m. and midnight Tuesday in Laramie, Wyoming (pulp temperature 33°F)

  • between 10:00 a.m. and noon Wednesday in Lincoln, Nebraska (pulp temperature 34°F)

  • between 10:00 p.m. and midnight Wednesday in Joliet, Illinois (pulp temperature 34°F)

  • between 10:00 a.m. and noon Thursday in Brookville, Pennsylvania (pulp temperature 34°F)

until finally arriving at 6:30 p.m. Thursday in Bronx, New York where we stop and unload, and, following the same process, our truck instance invokes its notifyObservers method to update the east coast dispatcher instance that we have stopped here and that our pulp temperature is 34°F.

At this point, the east coast dispatcher no longer has any interest in being an observer of our truck, so it issues a command causing the east coast dispatcher instance to invoke the removeObserver of our truck instance.

Now consider that both the east and west coast dispatchers need to track not only the truck Ed and I are driving, but all of the other trucks as well. Accordingly, each dispatcher instance will be an observer to many truck instances at the same time.

Consider also that this computer system may also be made accessible (with the proper security authorizations in place, of course) to both shippers and customers interested in tracking their loads and by unloading crews who may want to know whether a truck is still on schedule. They would translate into instances of shippers, customers, and loading crews, which would register and remove themselves as observers to specific trucks.

This constitutes quite an improvement over the old process where drivers called the dispatcher only once a day. Figure 13-2 shows the corresponding UML diagram showing the relationship between the west coast dispatcher and truck 440.

A447555_1_En_13_Fig2_HTML.jpg
Figure 13-2. UML class diagram for the Observer design pattern applied to the transportation scenario

Uses of the Observer Pattern in Technology Today

These days, in the realm of personal computing, the Observer pattern can be recognized in the RSS feed model, where you decide which feeds you want to subscribe to and the publisher keeps you informed of changing information. In the realm of social media, the Observer pattern can be recognized in the Twitter model, where you establish an account on Twitter and then decide to follow (subscribe) the tweets (publications) of another user. It can even be recognized with email, where broadcast messages are sent to a list of email addresses, often with a statement notifying the recipient how to unsubscribe from the broadcasts.

Exchanging Information Between Subject and Observer

With the Observer design pattern, there are two techniques by which a subject can exchange information with its observers:

  • The push technique

  • The pull technique

With push, the subject sends (pushes) its state values with the invocation of the update method of the observer. The observer gets all of its information through the update method. This is the technique we saw used with the Carretta Trucking system, where each time the truck stopped, its corresponding truck instance would invoke the update method of each of its observer instances and push to them the location of the truck and the pulp temperature of the cargo.

With pull, the subject essentially sends no state information when invoking the update method of the observer. Upon getting notified of a change in state through its update method, the observer instance makes a call to the subject to request (pull) the state information it seeks.

Many object-oriented scholars regard the pull technique as more elegant and flexible than the push technique. With push, every observer must accept all information the subject chooses to send it, regardless whether the observer needs that information. With pull, each observer can pick and choose which fragments of information it wants to know, but needs to make a subsequent call to get them. Both techniques have an impact on the signature of the update method, and pull has a subsequent effect on defining additional methods by which an observer can request change-of-state information from the subject. A case can be made to use the pull technique with our Carretta Trucking example when one considers that an unloading crew, registering itself as an observer, is interested only in whether the truck is running on time, and not with the pulp temperature of the cargo.

Observer Design Pattern in ABAP

It is entirely unnecessary to define Subject and Observer interfaces and to implement them in respective concrete subject and concrete observer classes in ABAP. This is because the Observer design pattern is implemented directly into the ABAP language itself, through events defined for classes . This is not to suggest that we are prohibited from using these Observer design pattern concepts to define such entities and interactions if we so choose, but only that doing so gains very little beyond the capabilities offered through the corresponding ABAP language statements.

Table 13-2 shows a comparison of the elements composing the Observer design pattern and for each of its counterparts in the ABAP language.

Table 13-2. Comparison of the Elements Composing the Observer Design Pattern and Counterparts in the ABAP Language

Observer design pattern element

ABAP language statement equivalent

Implementing the update method in the observer class

METHODS meth FOR EVENT evt OF cif IMPORTING parm1 parm2 …

This statement appears in the definition of the observer class or interface and references an event (evt) triggered by the subject class or interface (cif). Here, the name of the method does not need to be known to the subject , as is the case with the update method defined by the Observer interface of the Observer design pattern. Instead, this statement enables associating the name of any method of an observer class with an event raised by a subject class. The signature of the method is dependent on the signature of the corresponding event it is observing. A reference to the invoking subject class is available in the implicit parameter SENDER and does not need to be defined in the method signature. A method signature facilitates the push technique . A corresponding implementation must be provided for this method. This statement correlates to the design-time preparation for subscribing.

Invoking the subject method registerObserver by the observer class

SET HANDLER handler1 handler 2 … ACTIVATION “X”

Here, handler is the name of a method defined on a METHODS … FOR EVENT statement, which qualifies the type of subject class and its specific event to be observed. With this statement the observer class not only registers as an observer of the subject but also indicates the names of the update methods to be invoked when the subject notifies its observers. If not otherwise specified, ACTIVATION “X” is the default. This statement correlates to the runtime request to subscribe.

Invoking subject method removeObserver by observer class

SET HANDLER handler1 handler 2 … ACTIVATION “ ”

This statement correlates to the runtime request to unsubscribe.

(No counterpart in Observer design pattern)

EVENTS evt EXPORTING …

This statement is defined in the subject class and advertises to potential observer classes those events it is capable of triggering. Observer classes may pick and choose those events of the subject class it is interested in observing. This statement correlates to the design-time preparation for publishing.

Invoking subject method notifyObservers by subject class

RAISE EVENT evt EXPORTING …

This statement is how a subject class indicates a change in state, causing all of its observers to be notified accordingly. This statement correlates to the runtime request to publish.

There is one significant difference between the Observer design pattern and the corresponding implementation provided by ABAP language statements. With the Observer design pattern, each subject class retains its own list of observers, each observer to have its update method invoked when the subject class changes state . Accordingly, the subject class is aware of its observers. By contrast, subject classes using the ABAP statements EVENTS and RAISE EVENT are oblivious to the presence of any observer classes they may have. All of the management required to facilitate the Observer design pattern through the ABAP language statements takes place in the runtime environment. This is why with ABAP, a subject class does not need to provide the ABAP equivalent of implementations for the registerObserver, removeObserver, and notifyObservers methods.

Because ABAP provides statements to facilitate the observation of one instance by another, there is no need for us to define the subject and observer classes shown in the UML diagram above, but Listings 13-1 through 13-4 illustrate how we can define the truck and dispatcher classes in such a way that the dispatcher instance can respond to events raised by the truck instance.

The definition of the truck class, shown in Listing 13-1, plays the role of the ConcreteSubject participant, specifying public events for starting and stopping along with public methods start and stop.

Listing 13-1. Definition of truck Class
class truck definition.
  public section.
    events       : starting
                     exporting
                       value(current_driver)
                         type string
                 , stopping
                     exporting
                       value(location)
                         type string
                       value(pulp_temperature)
                         type int4
                 .
    methods      : constructor
                     importing
                       truck_id
                         type string
                 , start
                     importing
                       current_driver
                         type string
                 , stop
                     importing
                       location
                         type string
                       pulp_temperature
                         type int4
                 .
  private section.
    data         : truck_id       type string
                 , current_driver type string
                 , location       type string
                 , pulp_temperature
                                  type int4
                 .
endclass.

The implementation of these public methods is shown in Listing 13-2, where each method raises its corresponding public event.

Listing 13-2. Implementation of truck Class
class truck implementation.
  method constructor.
    me->truck_id                  = truck_id.
  endmethod.
  method start.
    me->current_driver            = current_driver.
    " Notify observers this truck is now moving:
    raise event starting
     exporting
        current_driver            = me->current_driver.
  endmethod.
  method stop.
    me->current_driver            = space.
    me->location                  = location.
    me->pulp_temperature          = pulp_temperature.
    " Notify observers this truck is no longer moving:
    raise event stopping
      exporting
        location                  = location
        pulp_temperature          = pulp_temperature .
  endmethod.
endclass.

The definition of the dispatcher class is defined to track trucks and plays the role of the ConcreteObserver participant. As shown in Listing 13-3, its definition provides public methods to initiate and terminate the observation of truck instances. Notice that its private section defines an internal table for retaining information about trucks it is tracking as well as methods for responding to the starting and stopping events raised by the truck class.

Listing 13-3. Definition of dispatcher Class
class dispatcher definition.
  public section.
    methods      : constructor
                     importing
                       dispatcher_id
                         type string
                 , show_tracked_trucks
                 , start_observing_truck
                     importing
                       truck_instance
                         type ref to truck
                 , stop_observing_truck
                     importing
                       truck_instance
                         type ref to truck
                 .
  private section.
    types        : begin of truck_row
                 ,   truck_instance
                                  type ref
                                    to truck
                 ,   driver       type string
                 ,   last_date    type string
                 ,   last_time    type string
                 ,   last_location
                                  type string
                 ,   last_pulp_temperature
                                  type int4
                 , end   of truck_row
                 , truck_list     type standard table
                                    of dispatcher=>truck_row
                 .
    data         : dispatcher_id  type string
                 , trucks_being_tracked
                                  type dispatcher=>truck_list
                 .
    methods      : respond_to_truck_starting
                     for event starting
                            of truck
                     importing
                       current_driver
                       sender
                 , respond_to_truck_stopping
                     for event stopping
                            of truck
                     importing
                       location
                       pulp_temperature
                       sender
                 .
endclass.

Implementations for the methods of the dispatcher class are shown in Listing 13-4.

Listing 13-4. Implementation of dispatcher Class
class dispatcher implementation.
  method constructor.
    me->dispatcher_id             = dispatcher_id.
  endmethod.
  method respond_to_truck_starting.
    data         : truck_entry    type dispatcher=>truck_row
                 .
    " Indicate corresponding truck entry is now moving:
    truck_entry-driver            = current_driver.
    truck_entry-last_date         = sy-datum.
    truck_entry-last_time         = sy-uzeit.
    modify me->trucks_being_tracked
      from truck_entry
      transporting driver
                   last_date
                   last_time
     where truck_instance         eq sender.
  endmethod.
  method respond_to_truck_stopping.
    data         : truck_entry    type dispatcher=>truck_row
                 .
    " Indicate corresponding truck entry is no longer moving:
    truck_entry-driver            = space.
    truck_entry-last_date         = sy-datum.
    truck_entry-last_time         = sy-uzeit.
    truck_entry-last_location     = location.
    truck_entry-last_pulp_temperature
                                  = pulp_temperature.
    modify me->trucks_being_tracked
      from truck_entry
      transporting driver
                   last_date
                   last_time
                   last_location
                   last_pulp_temperature
     where truck_instance         eq sender.
  endmethod.
  method show_tracked_trucks.
    data         : truck_entry    type dispatcher=>truck_row
                 .
    write: /01 'Dispatcher id:'
         , me->dispatcher_id
         .
    loop at me->trucks_being_tracked
       into truck_entry.
      write: /05     truck_entry-driver
           ,  25     truck_entry-last_date
           ,  35     truck_entry-last_time
           ,  45     truck_entry-last_pulp_temperature
           ,  55     truck_entry-last_location
           .
    endloop.
  endmethod.
  method start_observing_truck.
    data         : truck_entry    type dispatcher=>truck_row
                 .
    " Prepare new truck entry:
    truck_entry-truck_instance    = truck_instance.
    " Register this dispatcher instance as an observer to this truck:
    set handler me->respond_to_truck_starting
                me->respond_to_truck_stopping
            for truck_entry-truck_instance.
    " Place new truck entry into the list:
    append truck_entry
        to me->trucks_being_tracked.
  endmethod.
  method stop_observing_truck.
    data         : truck_entry    type dispatcher=>truck_row
                 .
    " Find corresponding truck entry in the list:
    read table me->trucks_being_tracked
      into truck_entry
      with key truck_instance     = truck_instance .
    " Remove this dispatcher instance as an observer to this truck:
    set handler me->respond_to_truck_starting
                me->respond_to_truck_stopping
            for truck_entry-truck_instance
                activation space.
    " Discard corresponding truck entry from the list:
    delete table me->trucks_being_tracked
      from truck_entry.
  endmethod.
endclass.

Notice the use of the set handler statement indicating both the instance of the truck for which observation is to begin or end as well as the names of the private methods to be invoked in response to the public events raised by instances of the truck class. These private methods have been defined with the for event clause indicating the applicable event to which each one is to respond. Although defined in the private section, both methods can be invoked externally once they have been registered to respond to external events. This is because their non-public visibility only prevents external entities from directly accessing these methods, but direct method calls are not occurring when events processing is being used.

Notice also the use of sender with the private methods. Sender is an undeclared signature parameter implicitly available to any method having a for events clause and will hold a reference to the instance raising the event. In the code above, it is used to determine which of the many truck instances is raising the starting or stopping event.

The snippet of report code shown in Listing 13-5 shows an example of using the components defined above.

Listing 13-5. Snippet of Report Code to Demonstrate Using the Events of Classes
o
o
data           : truck_440      type ref to truck
               , truck_441      type ref to truck
               , truck_442      type ref to truck
               , west_coast_dispatcher
                                type ref to dispatcher
               .
create object truck_440
  exporting truck_id            = '440'.
create object truck_441
  exporting truck_id            = '441'.
create object truck_442
  exporting truck_id            = '442'.
o
o
create object west_coast_dispatcher
  exporting dispatcher_id       = 'west'.
o
o
call method west_coast_dispatcher->start_observing_truck
  exporting: truck_instance     = truck_440
           , truck_instance     = truck_441
           , truck_instance     = truck_442
           .
o
o
call method truck_440->stop
  exporting location            = 'Las Vegas, NV'
            pulp_temperature    = 35
            .
call method truck_441->stop
  exporting location            = 'Chicago, IL'
            pulp_temperature    = 34
            .
call method truck_442->stop
  exporting location            = 'Boston, MA'
            pulp_temperature    = 33
            .
call method truck_440->start
  exporting current_driver      = 'Kading'.
o
o
call method west_coast_dispatcher->show_tracked_trucks.

Notice first in Listing 13-5 the creation of three truck objects and a single dispatcher object into their respective class reference variables. This is followed by the request by the dispatcher instance to start observing all three of the truck instances. One by one, each truck instance has its stop behavior invoked, indicating the truck’s location and the corresponding pulp temperature of the freight. This is followed by the start behavior of truck instance 440, indicating the name of the driver behind the wheel as the truck gets underway. Finally, the show_tracked_trucks method of the dispatcher instance is invoked to show the current status of all trucks being tracked.

Notice also there are only two invocations to methods of the dispatcher instance: one for it to start observing trucks and another for it to produce a report on the current status of the trucks it is tracking. In between these two method invocations are nothing but calls to behaviors of truck instances, yet with each call, the dispatcher instance was notified of the change and was able to update its tracking information, which subsequently is shown in the report produced by the call to method show_tracked_trucks of the dispatcher instances.

In addition, notice that the truck instances remained oblivious to the fact that they each had observers, and that the dispatcher instance makes no direct calls to any methods of any of the truck instances.

Summary

In this chapter, we learned how one class can establish itself as the observer of the changes taking place in another class, and that, unlike the design patterns we have already explored and others we’ll explore later, this observation capability is built into the ABAP language itself, alleviating the need for us to define our own set of classes to provide it. We’re now familiar with both the push and pull techniques characteristic of the Observer design pattern. In addition, we saw some examples of the practical uses of the Observer design pattern in current technology.

Observer Exercises

Refer to Chapter 10 of the functional and technical requirements documentation (see Appendix B) for the accompanying ABAP exercise programs associated with this chapter. Take a break from reading the book at this point to reinforce what you have read by changing and executing the corresponding exercise programs. There is one exercise program associated with this chapter: ZOOT303A.

Footnotes

1 At that time, Interstate Commerce Commission (ICC) regulations allowed for a driver to drive continuously for up to 10 hours, after which the driver must take an 8-hour break.

2 In those days, the nationwide maximum speed limit on U.S. interstate highways was 55 miles per hour.

3 This was a career change for me. Three days after returning from my final run I attended my first class of the summer semester at my local community college, where I began to study computer programming.

4 Whereas the business scenario is historically accurate, the new business requirement is merely hypothetical; I had left the company before the computerized tracking system was installed.

5 These days, GPS tracking technology makes this estimation technique unnecessary, and companies such as Qualcomm specialize in providing up-to-the-moment commercial fleet tracking systems.

6 GoF, p. 293.

7 GoF, p. 295.

8 Somewhere before arriving in Los Angeles Ed and I would have changed drivers, but we would not have made our usual 2-hour stop to do this.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset