이터레이터(Iterator) 패턴
집합 객체 내부 구조를 노출시키지 않고 순회 하는 방법을 제공하는 패턴
집합 객체를 순회하는 클라이언트 코드를 변경하지 않고 다양한 순회 방법을 제공할 수 있다.
이터레이터(Iterator) 패턴 before
Post
@Getter
public class Post {
private String title;
private final LocalDateTime createdDateTime;
public Post(String title) {
this.title = title;
this.createdDateTime = LocalDateTime.now();
}
}
Board
public class Board {
List<Post> posts = new ArrayList<>();
public List<Post> getPosts(){
return posts;
}
public void addPost(String content){
this.posts.add(new Post(content));
}
}
Client
public class Client {
public static void main(String[] args) throws InterruptedException{
Board board = new Board();
board.addPost("내용1");
Thread.sleep(100L);
board.addPost("내용2");
Thread.sleep(100L);
board.addPost("내용3");
Thread.sleep(100L);
// 들어간 순서대로 순회하기
List<Post> posts = board.getPosts();
for(int i = 0; i < posts.size(); i++){
Post post = posts.get(i);
System.out.println(post.getTitle());
}
// 가장 최신 글 먼저 순회하기
Collections.sort(posts, (o1, o2) -> o2.getCreatedDateTime().compareTo(o1.getCreatedDateTime()));
for(int i = 0; i < posts.size(); i++){
Post post = posts.get(i);
System.out.println(post.getTitle());
}
}
}
// 출력
내용1
내용2
내용3
내용3
내용2
내용1
현재 클라이언트 코드는 Board 클래스의 posts 구현체에 따라서 변경된다.
ex) ArrayList → Set
이터레이터 패턴을 적용해서 컬렉션의 내부 구조가 바뀌어도 클라이언트의 코드 변경 없이 순회 가능하도록 만들어 보자.
이터레이터(Iterator) 패턴 after
이미 ArrayList는 Iterator를 제공한다.
public class Board {
List<Post> posts = new ArrayList<>();
public void addPost(String content){
this.posts.add(new Post(content));
}
public Iterator<Post> getDefaultIterator(){
return this.posts.iterator();
}
}
public class Client {
public static void main(String[] args) throws InterruptedException{
// 생략 ...
// 들어간 순서대로 조회하기
Iterator<Post> iterator = board.getDefaultIterator();
while (iterator.hasNext()){
Post post = iterator.next();
System.out.println(post.getTitle());
}
}
}
이렇게 하면 나중에 Set 같은 다른 컬렉션 구조로 바뀌어도 클라이언트 코드 변경 없이 순회가 가능하다.
이터레이터 패턴 적용
RecentPostIterator - ConcreteIterator
public class RecentPostIterator implements Iterator<Post> {
private Iterator<Post> internalIterator;
public RecentPostIterator(List <Post> posts) {
posts.sort((p1, p2) -> p2.getCreatedDateTime().compareTo(p1.getCreatedDateTime()));
this.internalIterator = posts.iterator();
}
@Override
public boolean hasNext() {
return this.internalIterator.hasNext();
}
@Override
public Post next() {
return this.internalIterator.next();
}
}
최신글 순서대로 정렬해서 만들어지는 이터레이터
Board
public class Board {
List<Post> posts = new ArrayList<>();
public void addPost(String content){
this.posts.add(new Post(content));
}
public Iterator<Post> getDefaultIterator(){
return this.posts.iterator();
}
public Iterator<Post> getRecentPostIterator(){
return new RecentPostIterator(this.posts);
}
}
getRecentPostIterator() API가 추가
클라이언트
public class Client {
public static void main(String[] args) throws InterruptedException{
Board board = new Board();
board.addPost("내용1");
Thread.sleep(100L);
board.addPost("내용2");
Thread.sleep(100L);
board.addPost("내용3");
Thread.sleep(100L);
// 들어간 순서대로 조회하기
Iterator<Post> iterator = board.getDefaultIterator();
while (iterator.hasNext()){
Post post = iterator.next();
System.out.println(post.getTitle());
}
// 최신 글 순서대로 조회
Iterator<Post> recentIterator = board.getRecentPostIterator();
while (recentIterator.hasNext()){
Post post = recentIterator.next();
System.out.println(post.getTitle());
}
}
}
이제 클라이언트는 내부의 구체적인 구조를 몰라도 목적에 맞게 순회를 하는 이터레이터를 얻을 수 있다.
즉 내부의 구조가 바뀌어도 클라이언트 코드의 변경이 없다.
물론 ConcreteIterator인 RecentPostIterator는 변경된다.
이터레이터(Iterator) 패턴 정리
집합 객체 내부 구조를 노출시키지 않고 순회 하는 방법을 제공하는 패턴
장점
집합 객체가 가지고 있는 객체들에 손쉽게 접근할 수 있다
일관된 인터페이스를 사용해 여러 형태의 집합 구조를 순회할 수 있다
단점
클래스가 늘어나고 복잡도가 증가한다
이터레이터(Iterator) 패턴 적용 사례
자바
java.util.Enumeration과 java.util.Iterator
Java StAX (Streaming API for XML)의 Iterator 기반 API
XmlEventReader, XmlEventWriter
스프링
CompositeIterator
참고자료
'Computer Sience > Desgin Pattern' 카테고리의 다른 글
[Design Pattern] 메멘토(Memento) 패턴 (1) | 2024.11.07 |
---|---|
[Design Pattern] 중재자(Mediator) 패턴 (0) | 2024.11.04 |
[Design Pattern] 인터프리터(Interpreter) 패턴 (0) | 2024.10.31 |
[Design Pattern] 커맨드(Command) 패턴 (1) | 2024.10.31 |
[Design Pattern] 책임 연쇄(Chain of Responsibility) 패턴 (1) | 2024.10.31 |