Check out the Iterator design pattern implementation in ABAP Objects – another behavioral design pattern.
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:
- 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 an Iterator. 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 as Aggregate. 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?
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
I’ll write in next post on how to implement Linked List in OOABAP and use Iterator to process it.
[…] 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 […]
Nice post. The only thing which could be changed/enhanced here is implementing LCL_ITERATOR within LCL_COLLECTION, not outside it (of course assuming both classes are global). This way we would achieve strong coupling b/w both classes, but eventually LCL_ITERATOR is dedicated for IF_COLLECTION. So all the objects implementing this interface would be acceptable by LCL_ITERATOR->CONSTRUCTOR.
I described this global case here:
http://www.sdn.sap.com/irj/scn/weblogs?blog=/pub/wlg/25938
ArrayList in Java is designed that way, by means of an inner class.
Obviously we can’t achieve the similar in ABAP’s local class versions, so the only acceptable form is the one you lectured.
Thanks
Marcin
Wow, nice post on SDN. I don’t know how I missed that post.
It intense of creating LCL_ITERATOR as separate is to LOOSELY couple it. As on the same Collector, you could have more than one Iterator – one traversing from top to bottom, one for bottom to top, one for objects at even positions, etc.
If you have followed the next article for Iterator Iterator Design Pattern to access Linked List in ABAP Objects, the iterator is exactly same for both LCL_COLLECTION and LCL_LINKED_COLLECTION – as both needs same top to bottom traversal.
Regards,
Naimesh Patel
True. This way we can support serveral Iterators. I didn’t have chance to study next Iterator post yet, but surely will do this, as Linked List sounds as great fun 🙂
Thanks
marcin
It was a real good website..i had got valuable information.