What is an Iterator ?
Iterator design pattern is to provide a way to access the underlying object collection without exposing the underlying representations. Iterator decouples the logic to access the collection of objects out of the Collection object itselft. This decoupling provides added adavantage while traversing through the different type of collection objects.
Iterator also provides the flexibilty to traverse the collection in different ways based on the requirement. If we have position embeded within the Collection object itself, it wont allow us to achieve the multiple access in different ways. The iterator takes the responsibility for access out of the Collection object and put that within itself. The iterator provides a unique interface to access the underlying datastructure. Clients doesn’t need to know what type of collection object is being accessed.
Standard Classes – But not useful
Standard SAP has provided the classes, CL_OBJECT_COLLECTION for Object collection and CL_OBJECT_COLLECTION_ITERATOR for Iterator. The underlying interfaces are not generic enough for handing other type of collection options.
The biggest drawback of using these classes is:
The biggest drawback of using these classes is:
- Method GET_ITERATOR only returns the object type referrence to CL_OBJECT_COLLECTION_ITERATOR. This method should actually return the object type IF_OBJECT_COLLECTION_ITERATOR.
- Implementation of REMOVE method in class CL_OBJECT_COLLECTION is not efficient
- Required methods are not part of the interface like ADD, REMOVE etc.
So for this demo application, I would create similar interfaces and implementing classes which are more generic and can be used in different collection and iterator implementation.
UML
Lets check out this UML used for the demo application.
Components used in this UML:
- IF_ITERATOR – This provides the interface to access and traverse through the list. This component is anIterator. This object would have different methods to access the list in different manners.
- LCL_ITERATOR – This Concrete Iterator implements the interface IF_ITERATOR. This object contains all the logic for list access.
- IF_COLLECTION – This object has method to instantiate the iterator objects. This is also referred asAggregate. This interface contains all the methods for List manipulation like ADD, REMOVE, GET etc.
- LCL_COLLECTION – Implements the interface IF_COLLECTION as a Concrete Aggregate. This object would have a logic to instantiate proper iterator object. This object would also implements the list operation methods. Iterator would use methods e.g. GET to access particular object from the list.
Code Lines
Lets checkout the Code lines on how to implement the Iterator Design Patterns using ABAP. Best way to understand this example is to implement the code in SAP and debugging it through.
Iterator Design Pattern Demo
REPORT znp_dp_iterator. * CLASS lcl_item DEFINITION. PUBLIC SECTION. METHODS: constructor IMPORTING iv_name TYPE STRING. DATA: v_name TYPE STRING READ-ONLY. ENDCLASS. "lcl_item DEFINITION * CLASS lcl_item IMPLEMENTATION. METHOD constructor. v_name = iv_name. ENDMETHOD. "constructor ENDCLASS. "lcl_item IMPLEMENTATION * INTERFACE if_collection DEFERRED. * INTERFACE if_iterator. METHODS: get_index RETURNING VALUE(INDEX) TYPE i, has_next RETURNING VALUE(has_next) TYPE flag, get_next RETURNING VALUE(object) TYPE REF TO OBJECT, first RETURNING VALUE(object) TYPE REF TO OBJECT, set_step IMPORTING VALUE(iv_step) TYPE i. DATA: v_step TYPE i. DATA: v_current TYPE i. DATA: o_collection TYPE REF TO if_collection. ENDINTERFACE. "if_iterator IMPLEMENTATION * INTERFACE if_collection. METHODS: get_iterator RETURNING VALUE(iterator) TYPE REF TO if_iterator. METHODS: ADD IMPORTING element TYPE REF TO OBJECT, remove IMPORTING element TYPE REF TO OBJECT, CLEAR, SIZE RETURNING VALUE(SIZE) TYPE i, is_empty RETURNING VALUE(empty) TYPE flag, GET IMPORTING INDEX TYPE i RETURNING VALUE(object) TYPE REF TO OBJECT. ENDINTERFACE. "if_collection IMPLEMENTATION * CLASS lcl_iterator DEFINITION. PUBLIC SECTION. INTERFACES: if_iterator. METHODS: constructor IMPORTING io_collection TYPE REF TO if_collection. ALIASES: get_index FOR if_iterator~get_index, has_next FOR if_iterator~has_next, get_next FOR if_iterator~get_next, first FOR if_iterator~first, set_step FOR if_iterator~set_step. PRIVATE SECTION. ALIASES: v_step FOR if_iterator~v_step, v_current FOR if_iterator~v_current, o_collection FOR if_iterator~o_collection. ENDCLASS. "lcl_iterator DEFINITION * CLASS lcl_collection DEFINITION. PUBLIC SECTION. INTERFACES: if_collection. DATA: i_items TYPE STANDARD TABLE OF REF TO OBJECT. ALIASES: get_iterator FOR if_collection~get_iterator, ADD FOR if_collection~ADD, remove FOR if_collection~remove, CLEAR FOR if_collection~CLEAR, SIZE FOR if_collection~SIZE, is_empty FOR if_collection~is_empty, GET FOR if_collection~GET. ENDCLASS. "lcl_collection DEFINITION * CLASS lcl_collection IMPLEMENTATION. METHOD if_collection~get_iterator. CREATE OBJECT iterator TYPE lcl_iterator EXPORTING io_collection = me. ENDMETHOD. "if_collection~get_iterator METHOD if_collection~ADD. APPEND element TO i_items. ENDMETHOD. "if_collection~add METHOD if_collection~remove. DELETE i_items WHERE TABLE_LINE EQ element. ENDMETHOD. "if_collection~remove METHOD if_collection~CLEAR. CLEAR: i_items. ENDMETHOD. "if_collection~clear METHOD if_collection~SIZE. SIZE = LINES( i_items ). ENDMETHOD. "if_collection~size METHOD if_collection~is_empty. IF me->size( ) IS INITIAL. empty = 'X'. ENDIF. ENDMETHOD. "if_collection~is_empty METHOD if_collection~GET. READ TABLE i_items INTO object INDEX INDEX. ENDMETHOD. "if_collection~get ENDCLASS. "lcl_collection IMPLEMENTATION * CLASS lcl_iterator IMPLEMENTATION. METHOD constructor. o_collection = io_collection. v_step = 1. ENDMETHOD. "constructor METHOD if_iterator~first. v_current = 1. object = o_collection->get( v_current ). ENDMETHOD. "if_iterator~first METHOD if_iterator~get_next. v_current = v_current + v_step. object = o_collection->get( v_current ). ENDMETHOD. "if_iterator~next METHOD if_iterator~has_next. DATA obj TYPE REF TO OBJECT. DATA idx TYPE i. idx = v_current + v_step. obj = o_collection->get( idx ). IF obj IS BOUND. has_next = 'X'. ENDIF. ENDMETHOD. "if_iterator~isdone METHOD if_iterator~set_step. me->v_step = iv_step. ENDMETHOD. "if_iterator~SET_STEP METHOD if_iterator~get_index. INDEX = INDEX. ENDMETHOD. "if_iterator~get_index ENDCLASS. "iterator IMPLEMENTATION * CLASS lcl_main DEFINITION. PUBLIC SECTION. CLASS-METHODS: run. ENDCLASS. "lcl_main DEFINITION * CLASS lcl_main IMPLEMENTATION. METHOD run. * DATA: o_collection TYPE REF TO if_collection. DATA: o_iterator TYPE REF TO if_iterator. DATA: lo_item TYPE REF TO lcl_item. CREATE OBJECT o_collection TYPE lcl_collection. o_iterator = o_collection->get_iterator( ). CREATE OBJECT lo_item EXPORTING iv_name = 'Item1'. o_collection->add( lo_item ). CREATE OBJECT lo_item EXPORTING iv_name = 'Item2'. o_collection->add( lo_item ). CREATE OBJECT lo_item EXPORTING iv_name = 'Item3'. o_collection->add( lo_item ). CREATE OBJECT lo_item EXPORTING iv_name = 'Item4'. o_collection->add( lo_item ). CREATE OBJECT lo_item EXPORTING iv_name = 'Item5'. o_collection->add( lo_item ). "o_iterator->set_step( 2 ). WHILE o_iterator->has_next( ) IS NOT INITIAL. lo_item ?= o_iterator->get_next( ). WRITE: / lo_item->v_name. ENDWHILE. ENDMETHOD. "run ENDCLASS. "lcl_main IMPLEMENTATION START-OF-SELECTION. lcl_main=>run( ).
Should we implement Iterator in ABAP?
At first its seems too much overhead implementing the Iterator Design Pattern in ABAP as we have Iternal Tables. We can create internal tables which can contain the Objects and perform the operations like reading an entry, adding new entries, deleting entries etc. To implement the iterator design pattern, we need to create a separate Iterator object which would traverse through the collected objects in the collection. This collection would be generally the ITAB containg all the objects.
We should try to implement Iterator because,
- We could create as many iterator as we want to traverse objects in the different sequence.
- Linked List Object collection – When we need to use the Linked List type of the object collection, it would be difficult for every client to implement the accessing algorithm. Rather than that, we can create the Iterator and all clients can straight away use Iterator to access any object collection – ITAB or Linked List.
Do you agree on this?
No comments:
Post a Comment