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()를 호출해도 괜찮은지 조사하는 메소드로 이해하면 된다.

아래는 해당 소스.

The Factory Method Pattern (in ABAP)

20100512_factory_method
Factory의 요점은 다음과 같다.

  • ‘Product를 만드는 것’과 ‘등록’의 구현은 하위 클래스에서 수행한다.
  • (new를 사용해서) 실제의 인스턴스를 생성하는 대신에 인스턴스 생성을 위한 메소드를 호출함으로서(create_product) 구체적인 클래스명에 의한 속박에서 벗어나고 있다.

Framework 쪽: ZCL_FACTORY

Framework 쪽: ZCL_PRODUCT

ZCL_IDCARD_FACTORY

ZCL_IDCARD

그리고… 실행 프로그램 ZP_FACTORY_METHOD

이 실행 프로그램은 철저하게 암기할 필요가 있겠다.

The Template Method Pattern

20100504_template_method
상위 class의 templateMethod는 같은 class내에 정의된 method1 ~ method3를 이용한 알고리즘을 가지고 있다.
예를 들어 method1 ~ method3가 각각 open(), print(), close() 라면 templateMethod 내부는 다음과 같을 수 있다. (아래 display()가 templateMethod다)

[java]
public final void display() {
open();
for (int i = 0; i < 5; i++)
print();
close();
}
[/java]

실질적인 각 구현은 concrete class에서 담당하므로 파일을 열어서 쓰는 작업을 할 것인지 소켓을 열 것인지 하는 실제 처리내용은 어떤 concrete class를 쓰느냐에 달려있다. 상위 abstract class의 templateMethod에서는 열고, 프린트하고, 닫는 등 일련의 처리 흐름을 형성하는 것이 중요하다.
다시 말해, 상위 class에서 프로그램의 큰 흐름을 정하고 하위 class에서 구체적인 행동을 정한다.

상위 class가 처리 알고리즘을 담고 있어야 하기 때문에 interface를 이용할 수는 없다.

The Adapter Pattern (in ABAP)

(HFDP에서)
Duck의 object가 부족해서 Turkey의 object를 이용하려고 한다… 라는 이상한 상황을 가정하고 있다. 보통 기존 모듈이 새로운 모듈을 이용하려고 하나 서로 interface가 맞지 않을때 – 구체적으로, 한 클라이언트가 다른 object의 method를 이용하고 싶지만 기존 보유한 method를 바꾸고 싶진 않다(또는 바꿀 수 없다) 할 때… 같은 있음직한 상황을 예로 든다만.

어쨌건 이 경우 Duck은 client, Turkey는 Adaptee이다. TurkeyAdapter는 타겟 interface인 Duck를 구현하며 – 당연하다. Adapter니까 – 이때 Adaptee의 method들을 이용한다는 것이 포인트이다.

[text]
REPORT zp_adapter.

*PARAMETERS:

CLASS demo DEFINITION.

PUBLIC SECTION.
CLASS-METHODS: main,
test_duck IMPORTING i_duck TYPE REF TO zif_duck.

ENDCLASS. "demo DEFINITION

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

METHOD main.
DATA: gr_mallard_duck TYPE REF TO zcl_mallard_duck,
gr_wild_turkey TYPE REF TO zcl_wild_turkey,
gr_turkey_adapter TYPE REF TO zif_duck. " Adaptor for Duck
" i.e. Duck is the target interface

CREATE OBJECT gr_mallard_duck.
CREATE OBJECT gr_wild_turkey.
CREATE OBJECT gr_turkey_adapter TYPE zcl_turkey_adapter
EXPORTING
i_turkey = gr_wild_turkey.

WRITE: / ‘The Turkey says…’.
gr_wild_turkey->zif_turkey~gobble( ).
gr_wild_turkey->zif_turkey~fly( ).

SKIP 2.

WRITE: / ‘The Duck says…’.
test_duck( gr_mallard_duck ).

SKIP 2.

WRITE: / ‘The Turkey Adapter says…’.
test_duck( gr_turkey_adapter ).

ENDMETHOD. "demo

METHOD test_duck.
i_duck->quack( ).
i_duck->fly( ).
ENDMETHOD. "test_duck

ENDCLASS. "demo IMPLEMENTATION

START-OF-SELECTION.
demo=>main( ).
[/text]

test_duck은 Duck interface를 인자로 받는다. Adapter는 Duck interface를 구현한 것이므로 test_duck의 인자로 Adapter를 넘길 수 있고, 그 Adapter의 method들 안에서 Adaptee의 method가 호출된다.

Duck, Turkey, TurkeyAdapter 등의 Class 및 Interface 선언 및 구현은 그냥 시스템 내 Global Class를 이용하였다.
그래서, 여기서는 생략한다.