ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Iterator
    Java/디자인패턴 2020. 12. 20. 23:59

    순서대로 지정해서 처리하기

     

    본 글은 java 언어로 배우는 디자인 패턴 입문 교적을 바탕으로 기재한 내용입니다.


    반복문 for문을 살펴볼까?

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

    for 문에서 변수 i를 0으로 초기화 하여 arr 배열의 요소를 차례대로 처리해가며 배열arr 요소 전체를 검색하게 된다. 

     

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

    Iterator 패턴 이라고 한다. 

     

    다시 말해 Iterator 패턴이란, 무엇인가 많이 모여있는 것들을 순서대로 지정하면서 전체를 검색하는 처리를 실행하기 위한 것이다.

     

    - iterator : 무엇인가 '반복한다' 라는 의미, 반복자 라고 한다.

     

    예제 프로그램

    Agrregate 인터페이스

    집합체를 나타내는 인터페이스

    public interface Agrregate {
    	public abstract Iterator iterator();
    }

    Aggregate 인터페이스에서 선언되어 있는 메소드는 iterator 메소드 하나뿐이다.

    이 메소드는 집합체에 대응하는 Iterator를 1개 작성하기 위한 것이다.

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

     

    Iterator 인터페이스

    하나씩 나열하면서 검색을 실행하는 인터페이스

    public interface Iterator {
    	public abstract boolean hasNext();
    	public abstract Object next();
    }

    hasNext() : 다음 요소가 존재하면 true 이며 루프 종료 조건으로 사용된다.

    next() : 집합체의 요소를 1개 반환해준다. 또한 다음 요소를 반환하도록 진행시켜 주는 역할이 있다. (BookShelfIterator 참고)

     


    Book 클래스

    책을 나타내는 클래스

    public class Book {
        private String name;
        public Book(String name) {
        	this.name = name;
        }
        public String getName() {
        	return name;
        }
    }

    getName : 책이름 가져오기

    책이름은 생성자로 인스턴스 초기화시 인수로 지정한다.

     

    BookShelf 클래스

    서가를 나타내는 클래스

    구체적인 집합체 역할 : ConcreteAggregate

    public class BookShelf implements Aggregate {
    
        private Book[] books;
        private int last = 0;
        public BookShelf(int maxsize) {
        	this.books = new Boook[maxsize];
        }
        public Book getBookAt(int index) {
        	return books[index];
        }
      	public void appendBook(Book book) {
        	this.books[last] = book;
            last++;
        }
        public int getLength() {
        	return last;
        }
        public Iterator iterator() {
        	return new BookShelfIterator(this);
        }
    }

    books 필드 : 배열의 크기는 서가를 초기화 할때 maxsize를 받아서 생성하며 외부로부터 변경되는 것을 방지하기 위해 private 로 선언되었다. 

     

    * iterator() : 서가의 책을 하나씩 나열하고 싶을 때 iterator 메소드를 호출한다. 

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

     

    BookShelfIterator 클래스

    서가(BookShelf 클래스)의 검색하는 클래스

    구체적인 반복자 역할 : ConcreteIterator

    public class BookShelfIterator implements Iterator {
        private BookShelf bookShelf;
        private int index;
        public BookShelfIterator(BookShelf bookShelf) {
        	this.bookShelf = bookShelf;
            this.index = 0;
        }
        public boolean hasNext() {
        	if (index < bookShelf.getLength()) {
                return true;
            } else {
                return false;
            }
        }
        public Object next() {
            Book book = bookShelf.getBookAt(index);
            index++;
            return book;
        }
    }

    BookshelfIterator를 Iterator로서 다루기 위해 Iterator 인터페이스를 구현하고 있다. 

     

    bookShelf 필드 : BookShelfIterator가 검색할 서가이다.

    index 필드 : 현재 주목하고 있는 책을 가리키는 첨자이다.

    Constructor : 검색할 서가를 초기화하고, index도 0으로 초기화 한다.

    hasNext() : 첨자의 길이를 기준으로 서가의 길이와 비교하여 bool값을 반환한다.

    next() : 서가에 만들어 놓은 getBookAt을 통해 book을 반환하고 index를 다음으로 진행시킨다.

     

     

     

    Main 클래스

    public class Main {
        public static void main(String[] args) {
            BookShelf bookshelf = new BookShelf(4);
            bookshelf.appendBook(new Book("Around the World in 80 Days");
            bookshelf.appendBook(new Book("Bible");
            bookshelf.appendBook(new Book("Cinderella");
            bookshelf.appendBook(new Book("Daddy-Long-Legs");
            Iterator it - bookshelf.iterator();
            while (it.hasNext()) {
                Book book = (Book) it.next();
                System.out.println(book.getName());
            }
        }
    }

     

     

    왜 Iterator 패턴?

    단순히 배열을 for문을 이용해서 반복해도 되는데 집합체의 외부에 Iterator 역할을 만들어야 하나?

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

     

     

    main 클래서의 while 문은 BookShelf의 구현에는 신경쓰지 않는다. 

    만약 BookShelf 의 책관리를 배열이 아닌 java.util.Vector를 사용해서 관리를 한다고 해도 BookShelf가 iterator메소드를 가지고 있고 올바른 iterator를 반환해준다면 (즉, hasNext와 next메소드) while루프는 문제없이 돌아간다. 

     

    쉽게 말해 서가의 책관리 방식을 바꾼다 하더라도 iterator를 잘 동작하게 한다면 서가의 책을 모두 검색하는게 가능하다는 이야기이다. 

     

    이번 디자인 패턴을 시작으로 중요하게 생각해야할 점은

    추상클래스와 인터페이스를 사용하여 프로그래밍 하는 사고방식을 가져야 한다는 것이다.

     

    추상 클래스나 인터페이스의 사용을 안한다면 모든 문제를 구체적인 클래스만으로 해결하고 그로인해 클래스간의 결합이 강해져서 재사용성이 떨어지게 된다. 따라서 Aggregate 인터페이스를 구체화(상속)한 ConcreteAggregate 클래스, Iterator 인터페이스를 구체화(상속)한 ConcreateIterator 클래스를 사용하도록 하자.

     

    관련패턴

    Visitor 패턴

    Composite 패턴

    Factory Method 패턴

     

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

    Prototype  (0) 2021.01.01
    Singleton  (0) 2020.12.31
    Factory Method  (0) 2020.12.27
    Template Method  (0) 2020.12.22
    Adapter  (0) 2020.12.21
Designed by Tistory.