티스토리 뷰

JAVA/디자인 패턴

Iterator 패턴

kkoon9 2022. 3. 8. 22:54

Java 언어에서 배열 arr의 모든 요소를 표시하기 위해서는 다음과 같이 for 문을 사용한다.

for (int i = 0; i < arr.length; i++) {
		System.out.println(arr[i]);
}

for문의 i++같이 i를 하나씩 증가시키면 배열 arr의 요소 전체를 처음부터 차례대로 검색하게 된다.

여기에서 사용되고 있는 변수 i의 기능을 추상화해서 일반화한 것을 디자인 패턴에서는 Iterator 패턴이라 한다.

🐻 무엇인가 많이 모여있는 것들을 순서대로 지정하면서 전체를 검색하는 처리를 실행하기 위한 것

 

[예제 프로그램]

서가(BookShelf) 안에 책(Book)을 넣고, 그 책의 이름을 차례대로 표시하는 프로그램

  • Aggregate : 집합체를 나타내는 인터페이스
  • Iterator : 하나씩 나열하면서 검색을 실행하는 인터페이스
  • Book : 책을 나타내는 클래스
  • BookShelf : 서가를 나타내는 클래스
  • BookShelfIterator : 서가를 검색하는 클래스
  • Main : 동작 테스트용 클래스

Aggregate 인터페이스

Aggregate 인터페이스는 요소들이 나열되어 있는 집합체를 나타낸다.

이 인터페이스를 구현하고 있는 클래스는 배열과 같이 무엇인가가 많이 모여 있다.

Aggregate 인터페이스에서 선언되어 있는 iterator 메서드는 집합체에 대응하는 Iterator를 1개 작성하기 위한 것이다.

집합체를 하나씩 나열하고, 검색하고, 조사하고 싶을 때에는 iterator 메서드를 사용해서 Iterator 인터페이스를 구현한 클래스의 인스턴스를 1개 만든다.

Iterator 인터페이스

Iterator 인터페이스는 요소를 하나씩 나열하면서 루프 변수와 같은 역할을 수행한다.

  • hasNext() : 다음 요소가 존재하는지를 조사하기 위한 메서드
    • 즉, hasNext()는 루프의 조료 조건을 사용된다.
  • next() : 다음 요소를 얻기 위한 메서드
    • 다음 next()를 호출했을 때 정확히 다음 요소를 반환하도록 내부 상태를 다음으로 진행시켜 두는 역할이 있다.

구체적인 역할은 Iterator 인터페이스를 구현하고 있는 클래스(BookShelfIterator)에서 살펴보자.

Book 클래스

책을 나타내는 클래스

책 이름을 getName()에서 얻는 일만 수행한다.

책 이름은 생성자에서 인스턴스를 초기화할 때 인수로 지정한다.

BookShelf 클래스

서가를 나타내는 클래스

이 클래스를 집합체로 다루기 위해 Aggregate 인터페이스를 구현한다.

Aggregate 인터페이스에서 선언되어 있던 iterator 메서드가 기술되어 있는 것도 확인할 수 있다.

books 필드가 private인 것을 볼 수 있는데, 이 클래스 외부로부터 뜻하지 않게 변경되는 것을 방지하기 위해서다.

iterator 메서드는 BookShelf 클래스에 대응하는 Iterator로서, BookShelfIterator라는 클래스의 인스턴스를 생성해서 그것을 반환한다.

이 서가의 책을 하나씩 나열하고 싶을 때는 iterator 메서드를 호출한다.

BookShelfIterator 클래스

Iterator 인터페이스를 구현한다.

hasNext 메서드에서는 ‘다음 책'이 있으면 true, 없으면 false를 반환한다.

index 값과 bookShelf.getLength()의 값으로 판정한다.

Main 클래스

public class Main {
    public static void main(String[] args) {
        BookShelf bookShelf = new BookShelf(4);
        bookShelf.appendBook(new Book("Spring of Toby"));
        bookShelf.appendBook(new Book("Effective Java"));
        bookShelf.appendBook(new Book("Unit Test"));
        bookShelf.appendBook(new Book("Kotlin IN ACTION"));

        Iterator it = bookShelf.iterator();

        while (it.hasNext()) {
            Book book = (Book) it.next();
            System.out.println(book.getName());
        }
    }
}

위 코드를 실행시켜보면 다음과 같은 결과가 나온다.

위 예제 코드는 다음 링크에 있다.

https://github.com/kkoon9/Java-Design-Pattern/tree/master/src/iterator

Iterator 패턴의 핵심 키워드

예제 코드와 동작을 살펴봤으니 이젠 핵심 키워드를 살펴보자.

Iterator(반복자)- Iterator

요소를 순서대로 검색해가는 인터페이스(API)를 결정하는 역할을 한다.

hasNext()와 next()를 결정한다.

ConcreteIterator(구체적인 반복자) - BookShelfIterator

Iterator가 결정한 인터페이스(API)를 실제로 구현하는 역할을 한다.

이 역할은 검색하기 위해 필요한 정보를 가지고 있어야 한다.

예제 코드에서는 BookShelf 클래스의 인스턴스와 index 필드를 통해 정보를 가지고 있었다.

Aggregate(집합체) - Aggregate

Iterator 역할을 만들어내는 인터페이스(API)를 결정하는 역할을 한다.

이 인터페이스는 ‘내가 가지고 있는 요소를 순서대로 검색해주는 물체'을 만들어내는 메서드다.

이 물체가 바로 iterator 메서드다.

ConcreteAggregate(구체적인 집합체) - BookShelf

Aggregate가 결정한 인터페이스(API)를 실제로 구현하는 역할을 한다.

iterator 메서드를 구현한다.

🤔 왜 for문이 아닌 이런 번거로운 패턴을 사용하는걸까?

 

Iterator를 사용함으로써 구현과 분리해서 하나씩 셀 수 있기 때문이다.

다음 코드를 살펴보자.

while (it.hasNext()) {
    Book book = (Book) it.next();
    System.out.println(book.getName());
}

여기에서 사용되고 있는 것은 hasNext()와 next() 메서드뿐이다.

BookShelf의 구현에서 사용되고 있는 메소드는 호출되고 있지 않다.

결국 위 코드의 while 루프는 BookShelf의 구현에는 의존하지 않는다.

디자인 패턴은 클래스의 재이용화를 촉진한다.

재이용화를 촉진한다는 것은 클래스를 부품처럼 사용할 수 있게 하고, 하나의 부품을 수정해도 다른 제품에 큰 영향 없이 적은 수정만으로 끝낼 수 있다는 것을 의미한다.

🤔 인터페이스를 사용해야 하는 이유는 뭘까?

 

구체적인 클래스만 사용하면 클래스 간의 결합이 강해져서, 부품으로 재이용하는 일이 어렵다.

결합을 약하게 해서 부품으로 재이용하기 쉽도록 하기 위해 추상 클래스나 인터페이스을 도입한다.

추상 클래스나 인터페이스를 사용해 프로그래밍을 한다는 사고방식을 꼭 기억하자.

관련 패턴

  • Visitor 패턴
  • Composite 패턴
  • Fatory Method 패턴

'JAVA > 디자인 패턴' 카테고리의 다른 글

Template Method 패턴  (0) 2022.03.10
어댑터 패턴  (0) 2022.03.09
널(Null) 객체 패턴  (0) 2022.03.07
컴포지트(Composite) 패턴  (0) 2022.03.06
추상 팩토리(Abstract Factory) 패턴  (0) 2022.03.06
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
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
글 보관함