반응형

반복자 패턴(Iterator Pattern)

 

반복자 패턴 이터레이터 패턴이라고도 하고 Cursor라고도 한다.

즉, 대상으로 삼는 Context는 객체를 여러개 담고 있는 Aggregate Object(Collection Obj)이다.(ex : ArrayList)

 

이런 각각의 Aggregate Objelement를 방문을 원할 때 반복자 패턴을 이요한다.

하지만 Aggregate Obj의 구현 외부에는 노출되면 안된다는 전제가 있다.

 

일반적인 ArrayList나 Built-in Array를 쓰면 매 수정마다 Client 프로그램 수정이 계속 필요하다.

이를 개성하기 위해 Iterator 인터페이스를 하나만 구현한다면

클라이언트에서는 그에 맞게만 작성하면 되는 이점이 있다.

 

다시 말하자면 컬렉션 객체 안에 들어있는 모든 항목에 접근하는 방식이 통일되어 있으면 어떤 종류의 집합체에 대해서도 사용할 수 있는 다형적인 코드를 만들수 있다.

이터레이터 패턴을 사용하면 모든 항목에 일일이 접근하는 작업을 컬렉션 객체가 아닌 반복자 객체에서 맡게 된다

이렇게 하면 집합체의 인터페이스 및 구현이 간단해질 뿐 아니라, 집합체에서는 반복작업에서 손을 떼고 원래 자신이 할 일(객체 컬렉션 관리)에만 전념할 수 있다.

 

 

 

반복자 패턴에서 중요하게 여겨지는 디자인 원칙 SRP(Single Responsibility Principle)이다.

 

클래스는 단 하나만의 변경이 되어야하고 여러개면 분해해야 한다.(클래스 단일 책임 원칙)

 

 

 

반복자 패턴 클래스 다이어 그램

 

 

 

반복자 패턴 예제

 

Aggregate 인터페이스

추상 메서드를 하나 가지고 있다.

package IteratorPattern;

public interface Aggregate {
	public abstract Iterator createIterator();
}

 

 

 

Iterator 인터페이스

위의 클래스 다이어그램에 있는 3가지 메서드를 가진다.

package IteratorPattern;

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

 

 

 

CoffeeMenuIterator 클래스

위의 내용을 구현해두고 있다.

package IteratorPattern;

public class CoffeeMenuIterator implements Iterator{
	private CoffeeMenu coffeeMenu;
	private int index;
	
	public CoffeeMenuIterator(CoffeeMenu coffeeMenu) {
		this.coffeeMenu = coffeeMenu;
		this.index = 0;
	}

	@Override
	public boolean hasNext() {
		return index < coffeeMenu.getLength();
	}
	
	@Override
	public Object next() {
		Coffee coffee = coffeeMenu.getCoffee(index);
		index++;
		return coffee;
	}

	@Override
	public void remove() {
		coffeeMenu.removeCoffee(index);
	}
}

 

Coffee 클래스

Coffee에 대한 정보를 가진다.

package IteratorPattern;

public class Coffee {
	private String name;
	private int cost;
	
	public Coffee(String name, int cost) {
		this.name = name;
		this.cost = cost;
	}

	public String getName() {
		return name;
	}

	public int getCost() {
		return cost;
	}
}

 

 

 

CoffeeMenu 클래스

Coffee의 객체를 배열로 만들어 이용한다.

이때 CoffeeMenuIterator createIterator()을 통해 현재 객체를 보냄으로써 이터레이터 객체를 생성 할 수 있다.

package IteratorPattern;

public class CoffeeMenu implements Aggregate{
	private Coffee[] coffees;
	private int size = 0;
	
	public CoffeeMenu(int size) {
		coffees = new Coffee[size];
	}
	
	public Coffee getCoffee(int index) {
		return coffees[index];
	}

	public void addCoffee(Coffee coffee) {
		coffees[size] = coffee;
		size++;
	}
	public int getLength() {
		return size;
	}
	
	public void removeCoffee(int index) {
		if(index + 1 == size) {
			return;
		}
		for(int i = index; i < size - 1; i++) {
			coffees[i] = coffees[i + 1];
		}
		size--;
	}

	public CoffeeMenuIterator createIterator() {
		return new CoffeeMenuIterator(this);
	}
}

 

 

CoffeeMain 클래스

package IteratorPattern;

public class CoffeeMain {

	public static void main(String[] args) {
		CoffeeMenu coffeeMenu = new CoffeeMenu(3);

		coffeeMenu.addCoffee(new Coffee("아이스 아메리카노", 3000));
		coffeeMenu.addCoffee(new Coffee("아이스 라떼", 4000));
		coffeeMenu.addCoffee(new Coffee("더치 블랙", 3800));
		
		CoffeeMenuIterator iterator = coffeeMenu.createIterator();
		
		while(iterator.hasNext()) {
			Coffee coffee = (Coffee) iterator.next();
			System.out.println("커피 이름 : " + coffee.getName());
			System.out.println("커피 가격 : " + coffee.getCost());
		}
		
		System.out.println("=== Remove call ===");
		iterator = coffeeMenu.createIterator();
		iterator.remove();
		
		while(iterator.hasNext()) {
			Coffee coffee = (Coffee) iterator.next();
			System.out.println("커피 이름 : " + coffee.getName());
			System.out.println("커피 가격 : " + coffee.getCost());
		}
	}
}

 

물을 끓인다.
끓는 물에 에스프레소를 넣는다.
얼음을 넣는다.
시럽을 넣는다.
===
물을 끓인다.
끓는 물에 에스프레소를 넣는다.
얼음을 넣는다.
우유를 넣는다. 커피 이름 : 아이스 아메리카노
커피 가격 : 3000
커피 이름 : 아이스 라떼
커피 가격 : 4000
커피 이름 : 더치 블랙
커피 가격 : 3800
=== Remove call ===
커피 이름 : 아이스 라떼
커피 가격 : 4000
커피 이름 : 더치 블랙
커피 가격 : 3800

 

 

 

정리

 

컬렉션 구현 방법을 노출시키지 않으면서도 그 집합체 안에 들어있는 모든 항목에 접근할 수 있는 방법을 제공한다.

Iterator 패턴은 일련의 순서를 가진 데이터 집합에 대하여 순차적인 접근을 지원하는 패턴이다.

SRP 원칙을 따른다.

 

코드를 변경할 만한 이유가 두가지가 되면 그만큼 그 클래스를 나중에 고쳐야 할 가능성이 커지게 될 뿐 아니라, 

디자인에 있어서 두 가지 부분이 동시에 영향이 미치게 된다.

따라서 SRP 원칙에 따르면 한 역할은 한 클래스에서만 맡게 해야 한다.


 

반응형