Skip to content

The Iterator Pattern (in ABAP)

20100606_iterator

Iterator를 사용해서 구현과는 분리하여 하나 하나 요소들을 셀 수 있다.
아래 소스를 보면 loop를 돌 때 Iterator의 메소드만 이용하고 있으며 Aggregate 클래스가 어떤 식으로 구현되어 있는가 – 배열이든, 벡터든, Internal Table이든 – 는 상관없다. 즉 나중에 Aggregate의 요소 관리 방식을 얼마든지 바꿀 수 있다는 이야기.
이를 위해 아래와 같은 것들이 필요하다.

  • Iterator 인터페이스.
  • Aggregate 인터페이스. Iterator 인터페이스 타입의 객체를 리턴하는 메소드를 제공.
  • ConcreteIterator. Iterator 인터페이스를 구현한다. 구체적으로 어떤 놈을 어떻게 돌아야하는지 알고 있어야 하기 때문에 ConcreteAggregate의 객체를 내부에 가지고 있다.
  • ConcreteAggregate. Aggregate 인터페이스를 구현한다. 자신을 인자로 넘겨주면서 ConcreteIterator를 생성한다.

헷갈리기 쉬운게 Next()와 hasNext()인데,

  • Next() 호출시 현재 요소를 리턴하면서 내부적으로 다음 위치로 이동하게 된다.
  • hasNext()는 최후의 요소를 얻기 전에는 true를 리턴하고 최후의 요소를 얻은 후에는 false를 리턴한다. 다음에 Next()를 호출해도 괜찮은지 조사하는 메소드로 이해하면 된다.

아래는 해당 소스.


*&---------------------------------------------------------------------*
*& Report  ZP_ITERATOR
*&
*&---------------------------------------------------------------------*
*&
*&
*&---------------------------------------------------------------------*

REPORT  zp_iterator.

*PARAMETERS:

*----------------------------------------------------------------------*
*       INTERFACE lif_iterator
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
INTERFACE lif_iterator.
  TYPE-POOLS abap.

  METHODS: has_next RETURNING value(r_flag) TYPE abap_bool,
           next RETURNING VALUE(r_obj) TYPE REF TO object.

ENDINTERFACE.                    "lif_iterator

*----------------------------------------------------------------------*
*       INTERFACE lif_aggregate
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
INTERFACE lif_aggregate.

  METHODS iterator RETURNING VALUE(r_it) TYPE REF TO lif_iterator.

ENDINTERFACE.                    "lif_aggregate

*----------------------------------------------------------------------*
*       CLASS lcl_book DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_book DEFINITION.

  PUBLIC SECTION.
    METHODS: constructor IMPORTING i_name TYPE string,
             get_name RETURNING value(r_name) TYPE string.

  PRIVATE SECTION.
    DATA m_name TYPE string.

ENDCLASS.                    "lcl_book DEFINITION

*----------------------------------------------------------------------*
*       CLASS lcl_bookshelf DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_bookshelf DEFINITION.

  PUBLIC SECTION.
    INTERFACES lif_aggregate.
    METHODS: get_book_at IMPORTING i_idx TYPE i
                         RETURNING VALUE(r_book) TYPE REF TO lcl_book,
             append_book IMPORTING i_book TYPE REF TO lcl_book,
             get_length RETURNING value(r_last) TYPE i.

  PRIVATE SECTION.
    DATA: m_books TYPE STANDARD TABLE OF REF TO lcl_book,
          m_last TYPE i.

ENDCLASS.                    "lcl_bookshelf DEFINITION

*----------------------------------------------------------------------*
*       CLASS lcl_bookshelf_it DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_bookshelf_it DEFINITION.

  PUBLIC SECTION.
    INTERFACES lif_iterator.
    METHODS constructor IMPORTING i_bookshelf TYPE REF TO lcl_bookshelf.

  PRIVATE SECTION.
    DATA: m_bookshelf TYPE REF TO lcl_bookshelf,
          m_idx TYPE i VALUE 1.

ENDCLASS.                    "lcl_bookshelf_it DEFINITION

*----------------------------------------------------------------------*
*       CLASS lcl_book IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_book IMPLEMENTATION.

  METHOD constructor.
    m_name = i_name.
  ENDMETHOD.                    "constructor

  METHOD get_name.
    r_name = m_name.
  ENDMETHOD.                    "get_name

ENDCLASS.                    "lcl_book IMPLEMENTATION

*----------------------------------------------------------------------*
*       CLASS lcl_bookshelf IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_bookshelf IMPLEMENTATION.

  METHOD get_book_at.
    READ TABLE m_books INDEX i_idx INTO r_book.
  ENDMETHOD.                    "get_book_at

  METHOD append_book.
    APPEND i_book TO m_books.
  ENDMETHOD.                    "append_book

  METHOD get_length.
    r_last = lines( m_books ).
  ENDMETHOD.                    "get_length

  METHOD lif_aggregate~iterator.
    CREATE OBJECT r_it TYPE lcl_bookshelf_it EXPORTING i_bookshelf = me.
  ENDMETHOD.                    "lif_aggregate~iterator

ENDCLASS.                    "lcl_bookshelf IMPLEMENTATION

*----------------------------------------------------------------------*
*       CLASS lcl_bookshelf_it IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_bookshelf_it IMPLEMENTATION.

  METHOD constructor.
    m_bookshelf = i_bookshelf.
  ENDMETHOD.                    "constructor

  METHOD lif_iterator~has_next.
    IF m_idx <= m_bookshelf->get_length( ).
      r_flag = abap_true.
    ELSE.
      r_flag = abap_false.
    ENDIF.
  ENDMETHOD.                    "lif_iterator~has_next

  METHOD lif_iterator~next.
    r_obj = m_bookshelf->get_book_at( m_idx ).
    ADD 1 TO m_idx.
  ENDMETHOD.                    "lif_iterator~next

ENDCLASS.                    "lcl_bookshelf_it IMPLEMENTATION

*----------------------------------------------------------------------*
*       CLASS demo DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS demo DEFINITION.

  PUBLIC SECTION.
    CLASS-METHODS: main.

ENDCLASS.                    "demo DEFINITION

*----------------------------------------------------------------------*
*       CLASS demo IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS demo IMPLEMENTATION.

  METHOD main.
    DATA: lr_bookshelf TYPE REF TO lcl_bookshelf,
          lr_book_1 TYPE REF TO lcl_book,
          lr_book_2 TYPE REF TO lcl_book,
          lr_book_3 TYPE REF TO lcl_book,
          lr_book_4 TYPE REF TO lcl_book,
          lr_book_5 TYPE REF TO lcl_book,
          lr_it TYPE REF TO lif_iterator,
          lr_book TYPE REF TO lcl_book,
          lv_str TYPE string.

    CREATE OBJECT: lr_bookshelf,
                   lr_book_1 EXPORTING i_name = 'Around the world in 80 days',
                   lr_book_2 EXPORTING i_name = 'Bible',
                   lr_book_3 EXPORTING i_name = 'The Lord of the Rings',
                   lr_book_4 EXPORTING i_name = 'Jonathan Livingston Seagull',
                   lr_book_5 EXPORTING i_name = 'The Keys of the Kingdom'.

    lr_bookshelf->append_book( lr_book_1 ).
    lr_bookshelf->append_book( lr_book_2 ).
    lr_bookshelf->append_book( lr_book_3 ).
    lr_bookshelf->append_book( lr_book_4 ).
    lr_bookshelf->append_book( lr_book_5 ).

    lr_it = lr_bookshelf->lif_aggregate~iterator( ).

    WHILE lr_it->has_next( ) = abap_true.
      lr_book ?= lr_it->next( ).
      lv_str = lr_book->get_name( ).
      WRITE: / lv_str.
    ENDWHILE.
  ENDMETHOD.                    "main

ENDCLASS.                    "demo IMPLEMENTATION

START-OF-SELECTION.
  demo=>main( ).

Post a Comment

Your email is never published nor shared. Required fields are marked *