1. 예제 프로그램 - 책꽂이(BookShelf)에 책(Book)을 넣은 후, 순서대로 하나씩 다시 끄집어 내서 책 이름을 표시하는 프로그램
<Aggregate.java>
package ch01.Sample;
// 집합체는 자기 원소들을 돌아다닐 Iterator 객체를 반환하는
// iterator( ) 메소드를 가진다.
public interface Aggregate {
// 이 집합체의 Iterator를 반환하는 메소드
public abstract Iterator iterator();
}
// interface란, 모든 메소드의 body 부분이 없는 특수한 클래스이다.
<Iterator.java>
package ch01.Sample;
// 모든 Iterator가 가져야 할 메소드를 선언한 인터페이스
public interface Iterator {
// 원소가 더 있는지 검사할 때 사용되는 메소드
public abstract boolean hasNext();
public abstract Object next(); // 그 다음 원소를 얻어돌 때 사용되는 메소드
}
<Book.java>
package ch01.Sample;
// 책꽂이에 꽂힐 책을 나타내는 클래스
public class Book {
private String name = ""; // 책의 이름을 저장한다.
// 문자열을 입력 인자로 받아서 자신의 속성인 name에 저장한다.
public Book(String name) {
this.name = name;
}
// 자신의 이름을 반환하는 메소드
public String getName() {
return name;
}
}
<BookShelf.java>
package ch01.Sample;
public class BookShelf implements Aggregate {
// 책꽂이의 책을 보관하기 위한 Book 배열을 선언한다.
private Book[ ] books; //배열 변수만 선언하고, 공간을 할당되지 않았다.
private int last = 0; // 마지막 책이 꽂힌 위치를 저장한다.
public BookShelf(int maxsize) {
this.books = new Book[maxsize]; // 여기서 배열 공간을 실제로 만들었음.
}
// 입력인자인 index에 해당하는 책을 반환하는 메소드
public Book getBookFrom(int index) {
return books[index];
}
// 책꽂이에 책을 꽂는 메소드
public void appendBook(Book book) {
this.books[last] = book;
last++;
}
// 책꽂이의 책 개수를 반환하는 메소드
public int getLength() {
return last;
}
// 자신의 Iterator를 생성하여 반환하는 메소드
public Iterator iterator() {
// 자신을 인자로 하여 BookShelfIterator 객체를 생성하여 반환한다.
return new BookShelfIterator(this); //this: 현재 책꽂이
}
}
<BookShelfIterator.java>
package ch01.Sample;
// 책꽂이에 꽂힌 책을 차례차례 돌아다니는데 사용될 클래스
public class BookShelfIterator implements Iterator {
// 이 Iterator가 돌아다닐 책꽂이를 가리키는 속성
private BookShelf bookShelf;
// 현재 책 번호를 유지하는 속성
private int index;
// 입력인자인 BookShelf 객체를 자기 속성인 bookShelf에 저장한다.
// 나중에 이 속성을 이용해서 책꽂이를 돌아다닌다.
public BookShelfIterator(BookShelf bookShelf) {
this.bookShelf = bookShelf;
this.index = 0; // 책꽂이를 돌아다니기 전이므로, 0으로 초기화한다.
}
// 책꽂이에 접근할 책이 더 있는지 검사하는 메소드
public boolean hasNext() {
// 현재 책 번호가 책꽂이에 있는 책 개수보다 작으면,
// 책꽂이에 돌아다닐 책이 더 있는 것이므로 true를 반환한다.
if (index < bookShelf.getLength()) {
return true;
} else {
return false;
}
}
// 다음 책을 얻어오고자 할 때 호출되는 메소드
// 반환형이 Object 타입이다.
// - Object는 모든 클래스의 부모 클래스이므로 모든 자식을 가리킬 수 있다.
// - 즉, 모든 타입의 객체를 반환할 수 있다.
// - 실제로 반환되는 객체는 Book 타입이므로, 올바른 반환형으로 선언된 것이다.
public Object next() {
// 이 Iterator가 가리키는 책꽂이의 getBookAt(index)를 이용해서
// index 책번호에 해당하는 책을 얻어와서 book에 저장한다.
Book book = bookShelf.getBookFrom(index);
// 현재 책번호를 1 증가시킨다.
index++;
// 얻어온 책을 반환한다.
return book;
}
}
<Main.java>
package ch01.Sample;
public class Main {
// 모든 자바 프로그램은 main() 메소드부터 시작된다.
public static void main(String[] args) {
// 최대 4권의 책을 담을 수 있는 책꽂이를 생성한다.
BookShelf bookShelf = new BookShelf(4);
Aggregate bookShelf2 = new BookShelf(4);
// 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를 얻어온다.
// 실제 생성되는 객체의 타입은 BookShelfIterater이다.
Iterator it = bookShelf.iterator();
// 책이 계속해서 있으면 while 루프를 돈다.
// 책이 더 있는지 검사하기 위해서, iterator의 hasNext()를 호출한다.
while (it.hasNext()) {
Book book = (Book)it.next(); // 다음 책을 얻어온다.
// 위 문장 대신에
// Object book = it.next();
// 을 사용하면 안 된다.
// 왜냐하면, 아래에서 book.getName()을 호출하는데,
// Object 타입은 getName() 을 지원하지 않는다.
// 따라서, it.next( )가 반환한 Object 형을 Book 형으로 "강제형변환"해야 한다.
// 책의 이름을 출력한다.
System.out.println("" + book.getName());
}
// 책꽂이에 직접 접근해서 각 책을 얻어와서 책의 이름을 출력한다.
// iterator를 사용하지 않는다.
for(int i=0; i<bookShelf.getLength(); i++) {
Book book = bookShelf.getBookFrom(i);
System.out.println("" + book.getName());
}
}
}
2. 연습문제 - 책꽂이를 배열에서 벡터로
<Aggregator.java>
package ch01.A1;
// 집합체를 나타냄
public interface Aggregate {
// 집합체에 대응하는 Iterator 한 개를 생성하는데 사용될 메소드
// 어떤 집합체의 원소를 하나씩 열거하거나 조사하고자 할 때
// 이 메소드를 사용해서 Iterator 인터페이스를 구현한
// 클래스의 인스턴스를 한 개 얻어온다.
public abstract Iterator iterator();
}
<Iterator.java>
package ch01.Sample;
// 모든 Iterator가 가져야 할 메소드를 선언한 인터페이스
public interface Iterator {
// 원소가 더 있는지 검사할 때 사용되는 메소드
public abstract boolean hasNext();
public abstract Object next(); // 그 다음 원소를 얻어돌 때 사용되는 메소드
}
<Book.java>
package ch01.A1;
// 책을 나타내는 클래스
public class Book {
// 책이름을 저장하는 변수
private String name = "";
public Book(String name) {
this.name = name;
}
// 책의 이름을 얻어올 때 호출하는 메소드
public String getName() {
return name;
}
}
<BookShelf.java>
package ch01.A1;
// 책들을 보관하기 위해서 Vector를 사용한다.
import java.util.Vector;
// 책꽂이를 나타내는 클래스 = 집합체(aggregate)
public class BookShelf implements Aggregate {
// Book의 배열
// 이 배열의 크기는, 생성자(BookShelf( )) 호출 시 지정된다.
private Vector books;
public BookShelf(int initialsize) {
this.books = new Vector(initialsize);
}
public Book getBookAt(int index) {
return (Book) books.get(index);
}
// 책 한 권을 서가에 추가하는 메소드
public void appendBook(Book book) {
books.add(book);
}
// 현재 책꽂이에 있는 책의 개수를 반환하는 메소드
public int getLength() {
return books.size();
}
// 책꽂이의 책 하나하나를 끄집어내는 일을 하는
// BookShelfIterator를 생성하는 메소드
public Iterator iterator() {
return new BookShelfIterator(this);
}
}
<BookShelfIterator.java>
package ch01.Sample;
// 책꽂이에 꽂힌 책을 차례차례 돌아다니는데 사용될 클래스
public class BookShelfIterator implements Iterator {
// 이 Iterator가 돌아다닐 책꽂이를 가리키는 속성
private BookShelf bookShelf;
// 현재 책 번호를 유지하는 속성
private int index;
// 입력인자인 BookShelf 객체를 자기 속성인 bookShelf에 저장한다.
// 나중에 이 속성을 이용해서 책꽂이를 돌아다닌다.
public BookShelfIterator(BookShelf bookShelf) {
this.bookShelf = bookShelf;
this.index = 0; // 책꽂이를 돌아다니기 전이므로, 0으로 초기화한다.
}
// 책꽂이에 접근할 책이 더 있는지 검사하는 메소드
public boolean hasNext() {
// 현재 책 번호가 책꽂이에 있는 책 개수보다 작으면,
// 책꽂이에 돌아다닐 책이 더 있는 것이므로 true를 반환한다.
if (index < bookShelf.getLength()) {
return true;
} else {
return false;
}
}
// 다음 책을 얻어오고자 할 때 호출되는 메소드
// 반환형이 Object 타입이다.
// - Object는 모든 클래스의 부모 클래스이므로 모든 자식을 가리킬 수 있다.
// - 즉, 모든 타입의 객체를 반환할 수 있다.
// - 실제로 반환되는 객체는 Book 타입이므로, 올바른 반환형으로 선언된 것이다.
public Object next() {
// 이 Iterator가 가리키는 책꽂이의 getBookAt(index)를 이용해서
// index 책번호에 해당하는 책을 얻어와서 book에 저장한다.
Book book = bookShelf.getBookFrom(index);
// 현재 책번호를 1 증가시킨다.
index++;
// 얻어온 책을 반환한다.
return book;
}
}
<Main.java>
package ch01.Sample;
public class Main {
// 모든 자바 프로그램은 main() 메소드부터 시작된다.
public static void main(String[] args) {
// 최대 4권의 책을 담을 수 있는 책꽂이를 생성한다.
BookShelf bookShelf = new BookShelf(4);
Aggregate bookShelf2 = new BookShelf(4);
// 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를 얻어온다.
// 실제 생성되는 객체의 타입은 BookShelfIterater이다.
Iterator it = bookShelf.iterator();
// 책이 계속해서 있으면 while 루프를 돈다.
// 책이 더 있는지 검사하기 위해서, iterator의 hasNext()를 호출한다.
while (it.hasNext()) {
Book book = (Book)it.next(); // 다음 책을 얻어온다.
// 위 문장 대신에
// Object book = it.next();
// 을 사용하면 안 된다.
// 왜냐하면, 아래에서 book.getName()을 호출하는데,
// Object 타입은 getName() 을 지원하지 않는다.
// 따라서, it.next( )가 반환한 Object 형을 Book 형으로 "강제형변환"해야 한다.
// 책의 이름을 출력한다.
System.out.println("" + book.getName());
}
// 책꽂이에 직접 접근해서 각 책을 얻어와서 책의 이름을 출력한다.
// iterator를 사용하지 않는다.
for(int i=0; i<bookShelf.getLength(); i++) {
Book book = bookShelf.getBookFrom(i);
System.out.println("" + book.getName());
}
}
}