In the previous post, you have seen how to implement Iterator design Pattern. It also raised the question about the usefulness in ABAP as in ABAP, you have Internal Tables. The ITAB can handle all type of collection of objects easily. So, lets try to go away from ITAB usage for this post to see the Iterator. To have good understanding of the collection, today I’ll try to explain Iterator on Linked List.
So, lets get our hands dirty.
What is Linked List
Linked List is a Data Structure which contains Lot of interlinked nodes to form a sequence. Each node would contain generally two parts – Data Part and Pointer. Data Part contains the actual data object. The Next part contains the reference to the next object.
You can explore check out Linked List Wiki for more information.
To understand Linked List better, we’ll extend the program used in the Iterator design Pattern. So, if you haven’t yet read what is the Iterator pattern, this is the time to do so.
How to achieve this in ABAP
We’ll declare a class with two attributes: Object and Pointer. Something similar to shown in this image:
- Object would be a data part. This would be generic object which would reference to any object.
- Pointer would be a object reference to the next object in the list. This reference would be declared with the same reference type.
UML
Check out the UML for this demo. This UML only contains involved objects in Linked List.
These are the components in this UML:
- LCL_LINKED_LIST – This class represents a Linked List. It has a OBJ attribute which is Data Part contains the object reference to LCL_ITEM. It has a NEXT attribute which contains the reference to the next node in the list. Attribute NEXT is the same type as the Linked List.
- LCL_LINKED_COLLECTION – This class contains an attribute O_LINKED_LIST which contains the reference to First node in the Linked List. The First Node also referred as Head. This also contains other methods like ADD, REMOVE to manipulate the Linked List.
- LCL_LINKED_ITERATOR – This Iterator class contains the interface to traverse easily through the Collection.
- LCL_ITEM – This object represents the Data Part of the Node within the linked list.
Code Lines
I agree that the code lines it too long, but it is important to understand the use of same iterator interface to traverse through both collection – Collection of object using Internal table and Collection of object using Linked List. The best way to understand the program is via debugging.
Linked List using Iterator Design Patter in ABAP
REPORT ZNP_DP_ITERATOR_LLIST. * 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_linked_list DEFINITION. PUBLIC SECTION. DATA: obj TYPE REF TO object, next TYPE REF TO lcl_linked_list. ENDCLASS. "lcl_linked_list DEFINITION * CLASS lcl_linked_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_linked_collection DEFINITION. PUBLIC SECTION. INTERFACES: if_collection. DATA: o_linked_list TYPE REF TO lcl_linked_list. 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. PRIVATE SECTION. DATA: o_last_node TYPE REF TO lcl_linked_list. DATA: v_size TYPE i. ENDCLASS. "lcl_collection DEFINITION * CLASS lcl_linked_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. IF o_linked_list IS NOT BOUND. CREATE OBJECT o_linked_list. o_last_node = o_linked_list. ENDIF. DATA: o_next_node TYPE REF TO lcl_linked_list. CREATE OBJECT o_next_node. o_last_node->obj ?= element. o_last_node->next = o_next_node. o_last_node = o_next_node. v_size = v_size + 1. ENDMETHOD. "if_collection~add METHOD if_collection~remove. DATA: lo_node TYPE REF TO lcl_linked_list. DATA: obsolete_node TYPE REF TO lcl_linked_list. DATA: next_node TYPE REF TO lcl_linked_list. lo_node = o_linked_list. TRY. DO. IF lo_node->obj EQ element. EXIT. ENDIF. lo_node = lo_node->next. ENDDO. obsolete_node = lo_node->next. next_node = obsolete_node->next. lo_node->next = next_node. CATCH cx_root. WRITE: 'Unable to delete Next Node'. ENDTRY. v_size = v_size - 1. ENDMETHOD. "if_collection~remove METHOD if_collection~clear. CLEAR: o_linked_list. ENDMETHOD. "if_collection~clear METHOD if_collection~size. size = v_size. 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. DATA: lo_node TYPE REF TO lcl_linked_list. lo_node = o_linked_list. DO index TIMES. object = lo_node->obj. lo_node = lo_node->next. ENDDO. ENDMETHOD. "if_collection~get ENDCLASS. "lcl_collection IMPLEMENTATION * CLASS lcl_linked_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. * linked list CREATE OBJECT o_collection TYPE lcl_linked_collection. CREATE OBJECT lo_item EXPORTING iv_name = 'Linked List Item1'. o_collection->add( lo_item ). CREATE OBJECT lo_item EXPORTING iv_name = 'Linked List Item2'. o_collection->add( lo_item ). CREATE OBJECT lo_item EXPORTING iv_name = 'Linked List Item3'. o_collection->add( lo_item ). CREATE OBJECT lo_item EXPORTING iv_name = 'Linked List Item4'. o_collection->add( lo_item ). CREATE OBJECT lo_item EXPORTING iv_name = 'Linked List Item5'. o_collection->add( lo_item ). * Remove 4th object o_iterator = o_collection->get_iterator( ). DO 3 TIMES. lo_item ?= o_iterator->get_next( ). ENDDO. o_collection->remove( lo_item ). * Print all o_iterator = o_collection->get_iterator( ). 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( ).
Check out all Design Patterns
You may also want to explore all other Design Patterns in OO ABAP.
- ABAP Object Design Patterns – Singleton
- ABAP Objects Design Patterns – Model View Controller (MVC) Part 1
- ABAP Objects Design Patterns – Model View Controller (MVC) Part 2
- ABAP Objects Design Patterns – Model View Controller (MVC) Part 3
- ABAP Objects Design Patterns – Decorator
- ABAP Objects Design Patterns – Factory Method
- ABAP Objects Design Patterns – Observer
- Case Study: Observer Design Pattern Usage
- ABAP Objects Design Patterns – Abstract Factory
- OO Design Pattern Decorator – Why do we need to use helper variable?
- ABAP Objects Design Patterns – Facade
- ABAP Objects Design Patterns – Adapter
- ABAP Objects Design Patterns – Composite
- ABAP Objects Design Patterns – Iterator
- Iterator Design Pattern to access Linked List in ABAP Objects
- ABAP Objects Design Patterns – Proxy
- ABAP Objects Design Patterns – Prototype
- ABAP Objects Design Patterns – Singleton Factory
- ABAP Object Oriented Approach for Reports – Initial Design
- ABAP Object Oriented Approach for Reports – Redesign
- ABAP Objects Design Patterns – Builder
- ABAP Objects Design Patterns Singleton Usage
- ABAP MVC – Model View Controller Discussion
- Object Oriented Approach for Reports with multiple Datasource
- OO ABAP – Selection Object with Direct Access
- OO ABAP – Selection Criteria Object using RS_REFRESH_FROM_SELECT OPTIONS
- ABAP Factory Method Using SWITCH
[…] – Adapter ABAP Objects Design Patterns – Composite ABAP Objects Design Patterns – Iterator Iterator Design Pattern to access Linked List in ABAP Objects ABAP Objects Design Patterns – […]
hi, i’m reading your blog since today…good job!
From a performance’s point of view, do you know if the use of iterator, linked lists…that you describe is better than internal table?
Why (f.e.: linked list are created in ram, internal table use file system)? Have you got any idea of the boost (10%, 50%)?
We would choose if re-engine the code to increase performance or trying a completely different approch (night batch job)
thanks!!!!
Hello Lorenzo,
I don’t have much knowledge on how the internal tables are being processed on the kernel. But, I guess internal tables would be more convenient than the other options as they have more features like SORT, DELETE, INSERT. You can also create all of these operations in your linked list or object chain, but it would take more time to process.
Regards,
Naimesh Patel