반복자 패턴

문딤·2022년 7월 25일
0

반복자 패턴의 예시

반복자 패턴이란?


●Iterator : 집합체의 요소들을 순서대로 검색하기 위한 인터페이스 정의

● ConcreateIterator : Iterator 인터페이스를 구현함

● Aggregate : 여러 요소들로 이루어져 있는 집합체

● ConcreateAggregate : Aggreagate 인터페이스를 구현하는 클래스

Book 클래스

package DesignPattern.Iterator;

public class Book {
    private String name;

    public Book(String name){
        this.name = name;
    }

    public String getName(){
        return name;
    }
}

한권의 책에 대한 정보를 가지고 있는 클래스

Aggregate 인터페이스

package DesignPattern.Iterator;

import java.util.Iterator;

public interface Aggregate {
    Iterator createIterator();
}
집합체를 의미하는 인터페이스
Aggregate는 Iterator 역할을 만들어내는 인터페이스를 결정한다.

BookShelf 클래스

package DesignPattern.Iterator;

import java.util.Iterator;

public class BookShelf implements Aggregate{

private Book[] books;
private int last =0;

public BookShelf(int size){
    books = new Book[size];
}

public Book getBook(int index){
    return books[index];
}


    public int getLength() {
        return last;
    }

    // 책꽂이에 책을 꽂는다
    public void appendBook(Book book) {
        if (last < books.length) {
            this.books[last] = book;
            last++;
        } else {
            System.out.println("책꽂이가 꽉 찼습니다!");
        }
    }

    @Override
    public Iterator createIterator() {
        return new BookShelfIterator(this);
    }
}

책을 보관하는 책꽂이 역할을 하는 클래스
BookShelf는 이러한 Aggregate의 구현체이다.
실제로 책꽂이 안을 돌아다닐 Iterator를 생성하고 책꽂이를 관리하는 역할을 한다.

BookShelfIterator

package DesignPattern.Iterator;

import java.util.Iterator;

public class BookShelfIterator implements Iterator {


    private BookShelf bookShelf;
    private int index = 0;

    public BookShelfIterator(BookShelf bookShelf) {
        this.bookShelf = bookShelf;
    }

    @Override
    public boolean hasNext(){
        return index < bookShelf.getLength();
    }

    @Override
    public Book next() {
        Book book = bookShelf.getBook(index);
        index++;
        return book;
    }
}

BookShelf 클래스에서 검색을 수행하는 클래스
BookShelfIterator를 Iterator로 다루기 위해 Iterator 인터페이스를 상속받는다.

BookMain

public class BookMain {
    public static void main(String[] args) {


        BookShelf bookShelf = new BookShelf(10);


        Book book1 = new Book("문학동네");
        Book book2 = new Book("너무 한낮의 연애");
        Book book3 = new Book("늑대의 문장");

        bookShelf.appendBook(book1);
        bookShelf.appendBook(book2);
        bookShelf.appendBook(book3);


        System.out.println("현재 꽂혀있는 책 : "+bookShelf.getLength()+"권");

        Iterator it = bookShelf.createIterator();

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

콘솔 출력 결과

현재 꽂혀있는 책 : 3권
문학동네
너무 한낮의 연애
늑대의 문장

BookShelfIterator는 책꽂이에서 책을 한권씩 뽑아오는 역할을 한다.
검색할 책이 존재하는 동안 while문이 수행되며, it.next()에 의해 한권씩 책을 꺼내 이름을 출력한다.

반복자 패턴의 장단점

⭕<장점>

다양한 데이터 순회 알고리즘을 코드를 분리할 수 있다.(단일책임원칙,SRP)
기존 코드를 수정하지 않고도 새로운 타입의 콜랙션과 이터레이터를 추가할 수 있다. (개방/폐쇄원칙,OCP)
객체마다 이터레이터를 가지고 있기 때문에 같은 콜랙션을 병렬처리할 수 있다.
필요할 때, 순회(iteration)을 지연시키거나, 이어서 진행할 수 있다.

❌<단점>

간단한 컬랙션인 경우, 이터레이터 패턴을 적용하는 것은 과도할 수 있다.
콜랙션에서 특정 위치의 요소에 바로 접근해야 할 때, 이터레이터를 사용하는 것은 비효율적일 수 있다.

자바의 iterable 인터페이스

Collection 인터페이스와 List, Set, Queue 인터페이스의 계층구조는 알고 있었지만, Iterable이 Collection의 상위 인터페이스 인지는 잘 몰랐다.


public interface Collection<E> extends Iterable<E> {
  

Collection이 iterable을 상속받고 있음을 알 수 있다.

public interface Iterable<T> {
     Iterator<T> iterator();
  
    default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }

    default Spliterator<T> spliterator() {
        return Spliterators.spliteratorUnknownSize(iterator(), 0);
    }
}

iterable 내부에 forEach문과 Spliterator라는 default 메소드가 있음을 알 수 있다.
또한 인터페이스 답게 추상메소드로 iterator가 선언되어있었다.
덕분에
iterator() 메소드를 통해 for-each loop을 사용할 수 있게 되는 것이다.

따라서, Iterable 인터페이스의 역할은 iterator() 메소드를 하위 클래스에서 무조건 구현을 하게 만들기 위함인 것이라고 볼 수 있다.

자바의 iterator 인터페이스


public interface Iterator<E> {

    boolean hasNext();

    E next();

    default void remove() {
        throw new UnsupportedOperationException("remove");
    }


    default void forEachRemaining(Consumer<? super E> action) {
        Objects.requireNonNull(action);
        while (hasNext())
            action.accept(next());
    }
}

Iterator 인터페이스를 구현하고자 하는 클래스는
hasNext 메소드와 next 메소드를 override 하면 된다.

Collection과는 별개로 존재하는 인터페이스이다.
컬렉션 구현 방법을 노출시키지 않으면서도
그 집합체 안에 들어있는 모든 항목에 접근할 수 있는 방법을 제공해야 할 때 사용할 것

profile
풀스택개발자가 될래요

0개의 댓글