반응형
반복자 패턴이란?
컬렉션에는 리스트, 트리, 그래프 테이블 등등이 있다
리스트나 배열 같은 경우 단순히 반복문을 통해서 순차적으로 접근할 수 있지만 트리나 그래프 같은 경우 순회는 방법을 잡기 매우 애매해진다.
예를 들어 트리의 경우에도 깊이우선탐색, 너비우선탐색이 있으니 말이다.
이런 경우 이터레이터 패턴을 통해서 원소에 접근하는 방법을 추상화하여 이터레이터 패턴을 적용시킬 수 만 있다면 사용자가 원하는 방법으로 편하게 접근할 수 있게 된다.
접근하는 방법을 추상화하여 분리하였기 때문에 컬렉션의 내부 구조를 드러내지 않고 순차적으로 요소를 접근할 수 있게 된다.
패턴을 왜 사용해야 하는가?
- 컬렉션의 내부 구조를 숨길 수 있다. 즉, 내부 구조 및 순회방식을 알지 않아도 사용할 수 있다.
- 컬렉션의 구체적인 구현에 관계없이 동일한 방식으로 순회할 수 있다.
- 다양한 알고리즘을 컬렉션에 쉽게 적용할 수 있다
패턴을 언제 사용해야 하는가?
- 컬렉션의 요소를 순차적으로 처리해야 할때
- 여러 컬렉션에 객체 접근 방식을 통일하고자 할 때
- 컬렉션에 접근하는 방법을 다양하게 지원하고 싶을 때
- 클라이언트로부터 컬렉션의 구조를 숨기고 싶을 때
- 컬렉션의 종류를 변경할 가능성이 있을 때
문제점
- 반복자 클래스를 따로 만들어야 하기 때문에 복잡성이 증가할 수 있다.
구현 방법
간단하게 책을 관리하는 코드를 작성해 보았다.
package com.example.designpattern.behavioral.iterator.book;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.time.LocalDate;
@Data
@AllArgsConstructor
public class Book {
private String name;
private String author;
private LocalDate date;
}
package com.example.designpattern.behavioral.iterator;
import com.example.designpattern.behavioral.iterator.book.Book;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
public class NoPatternClient {
public static void main(String[] args) {
List<Book> bookshelf = new ArrayList<>();
bookshelf.add(new Book("객체지향의 사실과 오해", "조영호", LocalDate.of(2015, 6, 17)));
bookshelf.add(new Book("자바의 신", "이상민", LocalDate.of(2023, 10, 16)));
bookshelf.add(new Book("자바의 정석", "남궁성", LocalDate.of(2016, 1, 27)));
bookshelf.add(new Book("나미야 잡화점의 기적", "히가시노 게이고", LocalDate.of(2012, 12, 19)));
bookshelf.sort(Comparator.comparing(Book::getName));
for (Book book : bookshelf) {
System.out.println(book);
}
System.out.println("============================================");
bookshelf.sort(Comparator.comparing(Book::getDate));
for (Book book : bookshelf) {
System.out.println(book);
}
}
}
디자인 패턴을 적용하지 않으면 이처럼 클라이언트 쪽에서 직접 정렬하고 내부의 구현상태를 알고 있어야 한다. (name과 date가 있다는 것을 인지해야 함)
반복자 패턴을 적용하면 다음과 같이 수정할 수 있다.
먼저 반복자 인터페이스를 만들어 준다.
package com.example.designpattern.behavioral.iterator.iterator;
public interface Iterator<T> {
boolean hasNext();
T next();
}
package com.example.designpattern.behavioral.iterator.iterator;
import com.example.designpattern.behavioral.iterator.book.Book;
import java.util.Comparator;
import java.util.List;
public class NameIterator implements Iterator<Book> {
private List<Book> list;
private int index;
public NameIterator(List<Book> list) {
this.list = list;
this.list.sort(Comparator.comparing(Book::getName));
}
@Override
public boolean hasNext() {
return index < list.size();
}
@Override
public Book next() {
return list.get(index++);
}
}
package com.example.designpattern.behavioral.iterator.iterator;
import com.example.designpattern.behavioral.iterator.book.Book;
import java.util.Comparator;
import java.util.List;
public class DateIterator implements Iterator<Book> {
private List<Book> list;
private int index;
public DateIterator(List<Book> list) {
this.list = list;
this.list.sort(Comparator.comparing(Book::getDate));
}
@Override
public boolean hasNext() {
return index < list.size();
}
@Override
public Book next() {
return list.get(index++);
}
}
예시가 단순 List이기 때문에 클라이언트에서 직접 구현하는 게 더 간단해 보일 수 있는 것 같다.
하지만 컬렉션이 List가 아니라 복잡한 구조로 이뤄져 있다면 반복자패턴은 더욱 빛을 볼 것 같다.
package com.example.designpattern.behavioral.iterator;
import com.example.designpattern.behavioral.iterator.book.Book;
import com.example.designpattern.behavioral.iterator.book.Bookshelf;
import com.example.designpattern.behavioral.iterator.iterator.Iterator;
import java.time.LocalDate;
public class IteratorClient {
public static void main(String[] args) {
Bookshelf bookshelf = new Bookshelf();
bookshelf.addBook(new Book("객체지향의 사실과 오해", "조영호", LocalDate.of(2015, 6, 17)));
bookshelf.addBook(new Book("자바의 신", "이상민", LocalDate.of(2023, 10, 16)));
bookshelf.addBook(new Book("자바의 정석", "남궁성", LocalDate.of(2016, 1, 27)));
bookshelf.addBook(new Book("나미야 잡화점의 기적", "히가시노 게이고", LocalDate.of(2012, 12, 19)));
// 이름 순 이터레이터
Iterator<Book> nameIterator = bookshelf.getNameIterator();
while (nameIterator.hasNext()) {
System.out.println(nameIterator.next());
}
System.out.println("============================================");
// 날짜 순 이터레이터
Iterator<Book> dateIterator = bookshelf.getDateIterator();
while (dateIterator.hasNext()) {
System.out.println(dateIterator.next());
}
}
}
클라이언트 부분은 내부 구현상황을 몰라도 이처럼 손쉽게 요소들에 접근할 수 있게 된다.
실행 결과는 다음과 같다.
Book(name=객체지향의 사실과 오해, author=조영호, date=2015-06-17)
Book(name=나미야 잡화점의 기적, author=히가시노 게이고, date=2012-12-19)
Book(name=자바의 신, author=이상민, date=2023-10-16)
Book(name=자바의 정석, author=남궁성, date=2016-01-27)
============================================
Book(name=나미야 잡화점의 기적, author=히가시노 게이고, date=2012-12-19)
Book(name=객체지향의 사실과 오해, author=조영호, date=2015-06-17)
Book(name=자바의 정석, author=남궁성, date=2016-01-27)
Book(name=자바의 신, author=이상민, date=2023-10-16)
반응형
'Design Pattern > 행동 패턴(Behavioral patterns)' 카테고리의 다른 글
Observer Pattern, 옵저버 패턴 (0) | 2024.04.01 |
---|---|
Memento Pattern, 메멘토 패턴 (1) | 2024.03.27 |
Mediator Pattern, 중재자 패턴 (2) | 2024.03.07 |
Command Pattern, 커맨드 패턴 (1) | 2024.02.27 |
Chain of Responsibility Pattern, 책임 연쇄 패턴 (0) | 2024.02.27 |