ABAP Observer Design Pattern
Summary: This tutorial discusses about the Observer design pattern and how it is implemented in ABAP.
Problem
It is needed to maintain the consistency between related objects without making classes tightly coupled. For example, let’s say you have to develop a simple stock application that tracks price throughout the day in SAP. The stock’s prices information has to be displayed on a dashboard or sent via email or SMS to investors if it is below or above a certain price. Whenever the stock prices are changed, the dashboard has to reflect that changes and investors may get the SMS or email notification based on the price. To develop this application, we will leverage the observer design pattern so whenever the state of on object changes (stock’s price) the related objects ( dashboard, investors…) get notified.
Intent
Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
Observer Design Pattern UML Diagram
There are two actors in the observer design pattern:
- Subject. The subject object keeps track of its observers. In addition, the subject object provides an interface for register / unregister observer objects. Whenever the state of subject object changes, it notifies all of its observers immediately. In our example above, stock is an subject object.
- Observer: The observer object defines an interface for updating notification.
- ConcreteObserver: We can have multiple observer objects that inherit from the observer class or implements observer interface. In our example above, dashboard and investors are the Observer or ConcreteObserver objects.
ABAP Observer Design Pattern Implementation
Let’s implement Observer design pattern in ABAP. Here is the UML digram of ABAP observer design pattern that we will implement in the section below.
First, we define observer interface that provide method for updating notification:
INTERFACE if_observer. METHODS: notify IMPORTING im_param TYPE REF TO object. ENDINTERFACE. "if_observer
The if_observer interface contains only one method called notify that accepts any object as a parameter.
Second, we define the subject interface which we call observable. The observable interface provides methods for managing observer object.
INTERFACE lif_observable. METHODS: register IMPORTING im_observer TYPE REF TO if_observer, unregister IMPORTING im_observer TYPE REF TO if_observer. ENDINTERFACE. "lif_observable
Third, we can define a base class for all observable object that implement observable interface. A list of observer objects are stored in an internal table.
* CLASS cl_observable DEFINITION *----------------------------------------------------------------------* * Observable definition which implements observable interface *----------------------------------------------------------------------* CLASS cl_observable DEFINITION. PUBLIC SECTION. INTERFACES: lif_observable. ALIASES: register FOR lif_observable~register, unregister FOR lif_observable~unregister. METHODS: notifyobservers. PRIVATE SECTION. DATA: mt_observer TYPE STANDARD TABLE OF REF TO if_observer. ENDCLASS. "cl_observable DEFINITION *----------------------------------------------------------------------* * CLASS cl_observable IMPLEMENTATION *----------------------------------------------------------------------* * Observable implementation *----------------------------------------------------------------------* CLASS cl_observable IMPLEMENTATION. METHOD register. APPEND im_observer TO mt_observer. ENDMETHOD. "register METHOD unregister. DELETE TABLE mt_observer FROM im_observer. ENDMETHOD. "unregister METHOD notifyobservers. FIELD-SYMBOLS <observer> TYPE REF TO if_observer. LOOP AT mt_observer ASSIGNING <observer>. <observer>->notify( me ). ENDLOOP. ENDMETHOD. "notifyObservers ENDCLASS. "cl_observable IMPLEMENTATION
Fourth, we define stock class that inherits from the observable class. Whenever the price of the stock changes, we notify all of its observers.
*----------------------------------------------------------------------* * CLASS cl_stock DEFINITION *----------------------------------------------------------------------* * concrete observable definition *----------------------------------------------------------------------* CLASS cl_stock DEFINITION INHERITING FROM cl_observable. PUBLIC SECTION. METHODS: constructor IMPORTING im_name TYPE string im_price TYPE p, set_price IMPORTING im_price TYPE price_typ, get_price RETURNING value(re_price) TYPE price_typ, get_name RETURNING value(re_name) TYPE string. PRIVATE SECTION. DATA: mv_name TYPE string, mv_price TYPE price_typ. ENDCLASS. "cl_stock DEFINITION *----------------------------------------------------------------------* * CLASS cl_stock IMPLEMENTATION *----------------------------------------------------------------------* * concrete observable definition implementation *----------------------------------------------------------------------* CLASS cl_stock IMPLEMENTATION. METHOD constructor. super->constructor( ). " set name and price mv_name = im_name. mv_price = im_price. ENDMETHOD. "constructor METHOD set_price. IF im_price <> mv_price. mv_price = im_price. notifyobservers( ). " notify observer ENDIF. ENDMETHOD. "set_price METHOD get_price. re_price = mv_price. ENDMETHOD. "get_price METHOD get_name. re_name = mv_name. ENDMETHOD. "get_name ENDCLASS. "cl_stock IMPLEMENTATION
Finally, we define a dashboard class that simply displays the stock information.
*----------------------------------------------------------------------* * CLASS cl_dashboard DEFINITION *----------------------------------------------------------------------* * Concrete observer definition *----------------------------------------------------------------------* CLASS cl_dashboard DEFINITION. PUBLIC SECTION. INTERFACES if_observer. ALIASES: notify FOR if_observer~notify. ENDCLASS. "cl_dashboard DEFINITION *----------------------------------------------------------------------* * CLASS cl_dashboard IMPLEMENTATION *----------------------------------------------------------------------* * Concrete observer implementation *----------------------------------------------------------------------* CLASS cl_dashboard IMPLEMENTATION. METHOD notify. DATA: lv_name TYPE string, lv_price TYPE price_typ, lo_stock TYPE REF TO cl_stock. lo_stock ?= im_param. lv_name = lo_stock->get_name( ). lv_price = lo_stock->get_price( ). WRITE: / lv_name , 'currently has price $', lv_price. ENDMETHOD. "notify ENDCLASS. "cl_dashboard IMPLEMENTATION
Now, it is time to test our classes:
DATA: go_display TYPE REF TO cl_dashboard, go_stock TYPE REF TO cl_stock. START-OF-SELECTION. CREATE OBJECT go_stock EXPORTING im_name = 'IBM' im_price = '169.20'. CREATE OBJECT go_display. go_stock->register( go_display ). go_stock->set_price('169.21'). go_stock->set_price('161.23'). go_stock->set_price('160.01').
In this tutorial, you’ve learned how to implement ABAP observer design pattern to allow related objects get notified when state of an object changes.





