1. 반복자 패턴이란?

  • 반복자(Iterator) 패턴은 객체 지향 프로그래밍에서 반복자를 사용하여 컨테이너를 가로지르며 컨테이너의 요소들에 접근하는 패턴이다.

다시 말하자면, 집합체의 인터페이스 및 구현을 간단히 만들어주며, 집합체에서는 반복 작업에 손을 떼고 객체 컬렉션 관리에만 전념하게 해준다.

+ 반복자와 컨테이너란?

  • 반복자 : 객체 지향 프로그래밍에서 배열이나 그와 유사한 자료구조의 내부 요소를 순회하는 객체이다.
  • 컨테이너 : 같은 타입의 객체를 하나에 저장하는 집합의 개념이다.

일단 밑의 코드를 살펴보도록 하자.

String[] strArr = {Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec}; // 12월을 영어로 표기
//반복문 
for (int i = 0; i < str.lengh; i++) {
	System.out.println(strArr[i]);
}
//결과값
Jan
Feb
Mar
Apr
May
Jun
Jul
Aug
Sep
Oct
Nov
Dec

위의 코드를 따르면 strArr은 컨테이너를 지칭하는 단어이며, 반복자는 변수i를 지칭한다.
여기에서 변수i의 기능을 알아보자

변수 i

변수 i의 기능

1) 현재 실행하고 있는 배열의 위치를 나타낸다.
2) 값을 증가시켜 배열(컨테이너)의 모든 요소에 접근하도록 해준다.

위 코드에서 변수i가 하고 있는 기능을 추상화해서 일반화시킨 것을 반복자 패턴이라고 한다.
즉, 각기 다른 자료구조(컬렉션)들이 있다고 가정했을 때, 이 각각의 자료구조에 접근할 수 있는 방법을 모두 알 필요 없이 반복기능만 통일하여 일반화한 패턴이다.

반복자 패턴에서 중여시 여겨지는 객체 지향 프로그래밍의 5대 원칙(SOLID)은 S(단일 책임 원칙)이다.

반복자 패턴에 나오는 등장인물

1. 반복자(Iterator)

  • 요소를 순서대로 검색해가는 인터페이스를 결정
  • 다음 요소가 존재하는지를 얻기 위한 hasNext() 메서드와 다음 요소를 얻기위한 next() 메서드를 결정한다.

2. 구체적인 반복자(Concrete Iterator)

반복자가 결정한 인터페이스를 실제로 구현

3. 집합체(Aggregate)

반복자 역할을 만들어내는 인터페이스를 결정

4. 구체적인 집합체(Concrete Aggregate)

집합체 역할이 결정한 인터페이스를 실제로 구현


2. 반복자 패턴 구현

책꼿이에서 책을 꼿기도 하고 꺼내기도 한다고 생각해보자

  1. Aggregate 인터페이스
interface Aggregate {
    public abstract Iterator iterator();
}
  1. Iterator 인터페이스
interface Iterator {
    public abstract boolean hasNext(); //다음 요소가 존재하는지 확인하는 메서드
    public abstract Object next(); //다음 요소를 반환하는 메서드
}
  1. Book 클래스
class Book{
    private String bookName;
    //Book 생성자
    public Book(String bookName) {
        super();
        this.bookName = bookName;
    }
    //Getter 메서드
    public String getbookName() {
        return bookName;
    }
}
  1. bookShelf 클래스(feat.Aggregate 인터페이스)
class bookShelf implements Aggregate {
    private Book[] books;
    private int last = 0;
    //bookShelf 생성자
    public bookShelf(int MSize) {
        this.books = new Book[MSize];
    }
    //Book을 꺼내는 메서드
    public Book getBookAt(int idx) {//idx : 꺼낼 책의 (Book배열에서의)위치
    	return books[idx];
}
    //Book을 꼿는 메서드
    public void appendBook(Book book) {
        this.books[last] = book; // Book 배열에 0번째부터 매개 변수로 받는 book을 꼿는다
        last +=1; // 꼿고 나면 그 다음 칸에 꼿도록 last 변수를 늘려준다
    }
    //Book을 다 꼿았을 때, 마지막으로 들어간 책의 위치를 나타내주는 메서드(Book배열의 크기)
    public int getLength() {
        return last;
    }
    //bookShelf를 Iterater로 생성
    @Override
    public Iterator iterator() {
        return new bookShelfIterator(this);
    }
}
  1. bookShelfIterater 클래스(feat.Iterator 인터페이스)
class bookShelfIterator implements Iterator {
    private bookShelf  bookshelf;
    private int idx;
    //bookShelfIterator 생성자
    public bookShelfIterator (bookShelf bookshelf) {
        this.bookshelf = bookshelf;
    }
    //Iterator 인터페이스 안에 있는 추상 메서드 오버라이딩
    @Override
    public boolean hasNext() {
        //꺼내고자 하는 Book의 위치가 bookshelf.getLength()의 값보다 작으면 true 아니면 false
        return idx < bookshelf.getLength() ? true : false;
    }
    @Override
    //idx번째에 있는 Book 꺼내기
    public Object next() {
        Book book = bookshelf.getBookAt(idx);
        idx += 1;
        return book;
    }
}
  1. main 클래스
public class Client {
    public static void main(String[] args) {
        //5칸짜리 bookShelf객체 생성
        bookShelf bookshelf = new bookShelf(5);
        //5칸에 책 꼿기
        bookshelf.appendBook(new Book("돌이킬 수 없는 약속"));
        bookshelf.appendBook(new Book("눈보라 체이스"));
        bookshelf.appendBook(new Book("미움 받을 용기"));
        bookshelf.appendBook(new Book("봉제인형 살인사건"));
        bookshelf.appendBook(new Book("심판"));
        //Iterator 객체 생성 + 선언
        Iterator it = bookshelf.iterator();
        //반복문으로 책 꺼내기
        while (it.hasNext()) { // 다음 책이 존재할 때 까지(return값이 false면 종료)
            Book book = (Book)it.next();
            System.out.println(book.getbookName());
        }
    }
 }

3. 반복자 패턴의 장/단점

장점

  1. 크기가 큰 순회 알고리즘을 별도의 클래스로 추출하여 클라이언트 코드와 컬렉션을 정리한다 -> 단일 책임의 원칙
  2. 새로운 우형의 컬렉션 및 반복자를 구현함으로써 기존의 코드를 수정하지 않아도 된다 -> 개방-폐쇄의 원칙
  3. 각각의 반복자 객체는 그들만의 고유한 반복 상태가 포함되어 있기 때문에 동일한 컬렉션을 병렬로 반복 가능하다(동시에 가능하다)

단점

  1. 코드가 간단한 컬렉션으로만 짜여있다면, 반복자를 사용하는 것이 지나칠 우려가 있다.
  2. 반복자를 사용하는 것은 일부 특수 컬렉션의 요소를 직접 탐색하는 것보다 효율적인 측면에서 떨어진다.

4. 자바의 Iterator 인터페이스

1) Iterator 인터페이스는 컬렉션과는 별도로 제공하는 인터페이스이다.
2) hasNext(), next(), remove() 등과 같은 메서드를 제공한다.
3) 컬렉션 클래스의 데이터를 하나씩 읽고자 할때 사용한다.
4) 각각의 컬렉션이 일반화(=표준화)되어 있지 않을 때, 이들의 데이터를 읽고자 하면, 각각의 메서드를 알고 있어야 하는 번거로움을 줄이고자 Iterator 인터페이스를 사용한다
5) 재사용성을 극대화하는 것이 주된 목적이다.


5. 자바의 Iterable 인터페이스

Iterable 인터페이스는 terator 인터페이스의 메서드를 하위 클래스에서 무조건 구현하게 하기 위한 인터페이스이다.

profile
개발을 꿈꾸는 초짜

0개의 댓글