프로그래머는 일련의 비지니스 문제를 해결하기 위해 프로그램을 개발합니다.

(당연한 이야기지만, ㅡㅡ^)


이 때 비지니스 로직 중 가장 많이 사용하는 것은 아마 자료구조일 것이며, 수많은 목록형 데이터를 처리하기 위해 자료구조를 순회하며 행위를 수행하도록 작성하곤 합니다.


이를테면, 아래와 같이 말이죠?


1
2
3
4
5
6
List<String> nameList = Arrays.asList("강현지""남두현""유덕형""유형주");
        
for (String name : nameList) {
    // 리스트 목록을 순회하며, 데이터를 콘솔로 출력
    System.out.println(name);
}
cs


이와 같이 List 자체의 내부 구현 방법은 노출되어 있지 않지만, 내부의 데이터를 쉽게 순회할 수 있다는 것은 매력적입니다.

(즉 사용자는 ArrayList, LinkedList 의 내부 구현 상태는 알 필요가 없고, for-each 같은 순회 방법만 알면 됩니다.)


이와 같은 패턴을 Iterator 패턴(반복자 패턴)이라 부르며, 이번 포스팅에서는 이에 대한 예제와 함께 자세한 이야기를 다뤄보고자 합니다.


Iterator 패턴은 객체 내부의 특정 목록 데이터 순회하는 것이 목적이며, 흔히 아래와 같은 인터페이스를 구현하도록 하고 있습니다.

(아래 인터페이스는 java.util 패키지에 존재하는 Iterator 인터페이스 입니다.)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public interface Iterator<E> {
 
    /**
     * 다음 순회하고자 하는 객체가 존재하는가?
     *
     * @return
     */
    boolean hasNext();
 
    /**
     * 순회하고자 하는 다음 객체를 출력.
     * 
     * @return
     */
    E next();
}
cs


해당 인터페이스는 특정 목록 데이터를 순회하는 로직에 사용하는 메소드 서명들을 포함하고 있습니다. 

(다음 순회하는 항목이 있는가? 다음 항목으로 이동 등...)


이를 이용하여, 특정 클래스의 내부 목록을 순회하는 방법을 다음과 같이 서술해 볼 수 있을 것 같군요.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/**
 * 심플한 반복자의 구현
 *
 * Created by Doohyun on 2017. 8. 1..
 */
public class SimpleArrayIterator implements Iterator<String>{
 
    private String[] helloArray;
    private int position = 0;        // 현재 위치한 포지션의 index 관리
 
    public SimpleArrayIterator(String[] helloArray) {
        this.helloArray = helloArray;
    }
 
    /**
     * 현재 포지션이 길이 안에 존재하며 해당 배열의 값이 null 이 아닐 때, 다음 항목이 존재한다고 볼 수 있습니다.
     *
     * @return
     */
    @Override
    public boolean hasNext() {
        return position < helloArray.length && helloArray[position] != null;
    }
 
    /**
     * 다음 포지션으로 진행.
     *
     * @return
     */
    @Override
    public String next() {
        ++position;
        return helloArray[position - 1];
    }
}
cs


이렇게 구현한 반복자를 사용하는 방법은 종종 비지니스 로직을 작성하던 중 구현해 본 적이 있을 것입니다.


보통 Iterator 를 사용하여 순회하는 예제는 다음과 같이 제공하곤 합니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 목록 데이터.
String[] nameArray = {"강현지""남두현""유덕형""유형주"};
 
// 반복자 제작.
SimpleArrayIterator simpleArrayIterator = new SimpleArrayIterator(nameArray);
 
// 반복자를 이용하여, 순회.
while (simpleArrayIterator.hasNext()) {
    System.out.println(simpleArrayIterator.next());
}
 
// CONSOLE LOG
// 강현지
// 남두현
// 유덕형
// 유형주
cs


하지만, 보통 우리는 반복자를 이용하여 데이터를 순회하기 보다는 for-loop 를 통해 순회를 하곤 합니다. 


특히, JAVA5 부터 지원하는 새로운 형태의 for문을 종종 이용하곤 하는데요.

이 때 Java.lang.Iterable 인터페이스를 구현해주면, 새롭게 작성된 클래스도 해당 for 문을 사용할 수 있습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/**
 * Array 배열을 순회하는 반복가능 클래스 구현.
 *
 * Created by Doohyun on 2017. 8. 3..
 */
public class SimpleArrayIterable implements Iterable<String>{
 
    private String[] nameArray;
 
    public SimpleArrayIterable(String[] nameArray) {
        this.nameArray = nameArray;
    }
 
    /**
     * 반복자를 출력하도록 하고 있습니다.
     *
     * <pre>
     *     새로 작성된 for-loop 에서는 해당 반복자를 사용하도록 하고 있습니다.
     * </pre>
     *
     * @return
     */
    @Override
    public Iterator<String> iterator() {
        return new SimpleArrayIterator(nameArray);
    }
}
 
// 반복 가능 클래스 테스트 로직..
{
 
    // 목록 데이터.
    String[] nameArray = {"강현지""남두현""유덕형""유형주"};
 
    // 반복 가능 클래스의 인스턴스 제작.
    SimpleArrayIterable simpleArrayIterator = new SimpleArrayIterable(nameArray);
 
    // 새로운 형태의 for-loop 이용..
    for (String name : simpleArrayIterator) {
        System.out.println(name);
    }
 
}
cs


이로써, 예상할 수 있는 것은 모든 Collection 은 Iterable 을 구현하고 있다는 것을 알 수 있습니다.

모든 Collection 은 새로운 형태의 for-loop 을 사용할 수 있으니까요?


이와 같이, 알게 모르게 많은 사용하고 있던 Iterator 패턴은 [순회하는 방법을 캡슐화]하고 있습니다.

이는 Collection 의 내부 구현과 별도로 일관된 균일한 접근을 할 수 있도록 도와줄 수 있을 것 같습니다.

(꼭 Collection 이 아닌, Tree Graph 등 여러 자료구조를 탐색하는 것에도 사용할 수 있겠죠?)


이를 통해 꽤 괜찮은 컨셉의 비지니스 로직을 만들 수 있겠죠? ^^

한 번 이 글을 보고 실습해보면 나쁘지 않을 것 같습니다..... 



또한, 언제나 마무리 인사로,


"이 글을 보는 분들에게 도움이 되길 바랍니다. :-)"





반응형
Posted by N'