Observer Pattern
Observer pattern is a well known pattern especially with Java, here i continue my work in patterns.
This is my humble understanding of a way how we can apply observer pattern
The main components of this pattern is:
Observer pattern:
- Subject
- Observer
- Context
Why do we need?
Cant i do without this pattern, well of course you can do although you will be having a tightly coupled application
The main reason is we don't want to couple the objects
The main goal is the " Least knowledge in objects across each other"
The trick here is the use of the Events in ABAP where an event gets raised and then that will be handled by a listener!!
Subject:
Its the main object the core data that we will be working with
You could have multiple implementations of the subject
One approach: is to have an interface where we can extract the event.
Here is a code sample: Subject is data based on the sales order item data when there is a change it will fire the event below
interface lif_subject.
EVENTS: SUBJECT_IS_CHANGED.
ENDINTERFACE.
Here is the subject:
class lcl_subject definition .
public section.
INTERFACES lif_subject.
methods CONSTRUCTOR
importing
!IV_MATNR type MATNR
!IV_SPRAS type SPRAS
.
methods GET_MATNR
returning
value(RV_MATNR) type MATNR .
methods GET_SPRAS
returning
value(RV_SPRAS) type SPRAS .
methods SET_MATNR
importing
!IV_MATNR type MATNR .
methods SET_SPRAS
importing
!IV_SPRAS type SPRAS .
protected section.
private section.
data MV_MATNR type MATNR .
data MV_SPRAS type SPRAS .
ENDCLASS.
CLASS lcl_subject IMPLEMENTATION.
METHOD constructor.
mv_matnr = iv_matnr.
mv_spras = iv_spras.
ENDMETHOD.
METHOD get_matnr.
rv_matnr = mv_matnr.
ENDMETHOD.
METHOD get_spras.
rv_spras = mv_spras.
ENDMETHOD.
METHOD set_matnr.
mv_matnr = iv_matnr.
RAISE EVENT lif_subject~SUBJECT_IS_CHANGED.
ENDMETHOD.
METHOD set_spras.
mv_spras = iv_spras.
RAISE EVENT lif_subject~SUBJECT_IS_CHANGED.
ENDMETHOD.
ENDCLASS.
Observer:
Observer is the one thats interested in the change of the subject
That could be any observer
Here is the code sample
****Observer
INTERFACE lif_observer.
METHODS: update.
ENDINTERFACE.
class lcl_observer1 DEFINITION.
PUBLIC SECTION.
INTERFACES lif_observer.
ENDCLASS.
class lcl_observer1 IMPLEMENTATION.
method lif_observer~update.
WRITE:/ ' Observer 1 is updated '.
ENDMETHOD.
ENDCLASS.
class lcl_observer2 DEFINITION.
PUBLIC SECTION.
INTERFACES lif_observer.
ENDCLASS.
class lcl_observer2 IMPLEMENTATION.
method lif_observer~update.
WRITE:/ ' Observer 2 is updated '.
ENDMETHOD.
ENDCLASS.
Context: Its the manager of the all communication like a channel
It separates the observer from the observable.
class lcl_channel definition.
PUBLIC SECTION.
methods: add_observer IMPORTING io_observer type REF TO lif_observer.
methods: remove_observer IMPORTING io_observer type REF TO lif_observer.
methods: constructor.
methods: notify_observers FOR EVENT lif_subject~SUBJECT_IS_CHANGED of lcl_subject IMPORTING sender.
PRIVATE SECTION.
DATA: lo_list type REF TO CL_OBJECT_MAP.
class-DATA: lv_key type i.
ENDCLASS.
Notice that the event listener for the subject is the channel itself
and notify_observers method is responsible for that.
****Manager!!
class lcl_channel definition.
PUBLIC SECTION.
methods: add_observer IMPORTING io_observer type REF TO lif_observer.
methods: remove_observer IMPORTING io_observer type REF TO lif_observer.
methods: constructor.
methods: notify_observers FOR EVENT lif_subject~SUBJECT_IS_CHANGED of lcl_subject IMPORTING sender.
PRIVATE SECTION.
DATA: lo_list type REF TO CL_OBJECT_MAP.
class-DATA: lv_key type i.
ENDCLASS.
class lcl_channel IMPLEMENTATION.
method constructor.
create OBJECT lo_list.
lv_key = 1.
ENDMETHOD.
method add_observer.
lo_list->PUT(
EXPORTING
KEY = lv_key
VALUE = io_observer
).
lv_key = lv_key + 1.
ENDMETHOD.
method remove_observer.
ENDMETHOD.
METHOD notify_observers.
DATA: lo_map_iterator TYPE REF TO CL_OBJECT_COLLECTION_ITERATOR.
DATA: lo_observer type REF TO lif_observer.
break developer.
lo_map_iterator ?= lo_list->GET_VALUES_ITERATOR( ).
while lo_map_iterator->HAS_NEXT( ) = abap_true.
lo_observer ?= lo_map_iterator->GET_NEXT( ).
lo_observer->UPDATE( ).
ENDWHILE.
ENDMETHOD.
Notice the use of the Collections as well cl_object_collections object in SAP Standard
I hope you find this useful
The sample code is attached as a text file
ENDCLASS.