이터레이터 패턴
- 행위 패턴
- 컬렉션 구현 방법을 노출시키지 않으면서도 그 집합체 안에 들어있는 모든 항목에 접근할 수 있게 해주는 방법을 제공해 주는 패턴
- 이터레이터 패턴을 사용하면 집합체 내에서 어떤 식으로 일이 처리되는지 몰라도 그 안에 들어있는 항목들에 대해서 반복작업을 수행할 수 있다.
보통 프로그래밍을 하면서 반복문을 돌리려면 for문을 사용한다.
for (int i = 0; i < n; i++) {
System.out.println(array[i]);
}
for 문의 초기화문에서 흔희 사용되는 변수 i는 배열이 주어질 때 각각의 요소에 차례대로 접근하기 위해 사용된다.
이렇게 사용되는 변수 i의 역할을 추상화한 것이 Iterator 패턴이다.
이터레이터 패턴 사용 예시
- Iterator
- 집합체의 요소들을 순서대로 검색하기 위한 인터페이스
- ManagerIterator
- Iterator 인터페이스를 구현함
- Aggregate
- 여러 요소들로 이루어져 있는 집합체
- Manager
- Aggregate 인터페이스를 구현하는 클래스
public class Member {
private String name;
public Member(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
멤버의 이름을 가지고 있는 클래스이다.
public interface Aggregate {
Iterator createIterator();
}
Aggregate는 Iterator 역할을 만들어내는 인터페이스를 결정한다
public class Manager implements Aggregate{
private Member[] members;
private int last = 0;
public Manager(int size) {
members = new Member[size];
}
public Member getMember(int index) {
return members[index];
}
public int getLength() {
return last;
}
public void appendMember(Member member){
if (last < members.length) {
this.members[last] = member;
last++;
return;
}
System.out.println("멤버수가 가득 찼습니다.");
}
@Override
public Iterator createIterator() {
return new ManagerIterator(this);
}
}
Aggregate의 구현체이다.
멤버배열을 탐색할 Iterator를 생성하고 멤버들을 관리하는 역할을 한다.
public class ManagerIterator implements Iterator<Member> {
private Manager manager;
private int index = 0;
public ManagerIterator(Manager manager) {
this.manager = manager;
}
@Override
public boolean hasNext() {
return index < manager.getLength();
}
@Override
public Member next() {
Member member = manager.getMember(index);
index++;
return member;
}
}
Iterator를 구현하였다.
next()는 다음 요소를 반환하고, hasNext()는 검색을 계속 수행해도 될지의 여부를 판별한다.
public class Main {
public static void main(String[] args) {
Manager manager = new Manager(10);
Member member1 = new Member("member1");
Member member2 = new Member("member2");
Member member3 = new Member("member3");
manager.appendMember(member1);
manager.appendMember(member2);
manager.appendMember(member3);
System.out.println("현재 등록된 멤버 수 :" + manager.getLength() +"명");
Iterator it = manager.createIterator();
while (it.hasNext()){
Member member = (Member) it.next();
System.out.println(member.getName());
}
}
}
다음 멤버객체를 확인하기 위해 Iterator를 사용하였다.
실행결과
현재 등록된 멤버 수 :3명
member1
member2
member3
왜 사용하지?
for문으로 동일한 표현이 가능한데 왜 굳이 코드를 늘려가며 Iterator 패턴을 사용해야 하는지 의문이 들 수 있다.
Iterator 패턴을 사용하는 가장 큰 이유는 하나씩 꺼내서 처리하는 과정을 구현과 분리할 수 있기 때문이다.
Iterator 패턴을 사용함
while (it.hasNext()){
Member member = (Member) it.next();
System.out.println(member.getName());
}
for문을 사용함
for (int i = 0; i < manager.getLength(); i++) {
System.out.println(manager.getMember(i).getName());
}
이 두 가지 코드는 실행 시 Book 객체의 내용을 하나씩 꺼내서 보여주는 동일한 결과를 보여준다.
하지만 for문을 사용할 때와 달리 Iterator 패턴을 사용할 때는 어디까지나 Iterator의 메서드를 사용할 뿐 Manager의 구현에서 사용되고 있는 메서드는 호출되지 않고 있다.
즉, 1번 방식은 Manager의 구현에 의존하지 않는다.
Manager에 무언가 수정사항이 생기더라도 Manager가 올바른 Iterator를 반환하기만 한다면 while문이 사용되는 Main은 수정할 필요가 없다. 하나의 클래스를 수정하더라도 다른 클래스에 큰 영향 없이 작은 수정 만으로도 끝낼 수 있다는 것이다.
장단점
장점
- 집합체 클래스의 응집도를 높여준다.
- 집합체 내에서 어떤 식으로 일이 처리되는지 알 필요 없이, 집합체 안에 들어있는 모든 항목에 접근할 수 있게 해 준다.
- 모든 항목에 일일이 접근하는 작업을 컬렉션 객체가 아닌 이터레이터 객체에서 맡게 된다. 이렇게 하면, 집합체의 인터페이스 및 구현이 간단해질 뿐만 아니라, 집합체에서는 반복 작업에서 손을 떼고 원래 자신이 할 일에만 전념할 수 있다.
단점
- 단순한 순회를 구현하는 경우 클래스만 많아져 복잡도가 증가할 수 있다.
정리
- Iterator 패턴은 집합체의 요소를 순서대로 지정하면서 처리하는 방식
- Iterator(반복자) : 요소를 순서대로 검색하는 인터페이스를 결정
- ConcreteIterator(구체적인 반복자) : Iterator가 결정한 인터페이스를 실제로 구현한다. 검색하기 위해 필요한 정보를 가지고 있어야 한다.
- Aggregate(집합체) : Iterator 역할을 만드는 인터페이스를 결정한다.
- ConcreteAggregate(구체적인 집합체) : Aggregate 역할이 결정한 인터페이스를 실제로 구현한다.
'CS' 카테고리의 다른 글
인덱스 (3) | 2023.09.28 |
---|---|
트랜잭션과 잠금 (0) | 2023.09.26 |
프록시 패턴(Proxy Pattern) (0) | 2023.05.12 |
옵저버 패턴(Observer Parttern) (0) | 2023.05.11 |
전략 패턴(Strategy Pattern) (0) | 2023.05.10 |