Java 디자인 패턴-04.Iterators

(Java 디자인 패턴 스터디 모집 중 : https://github.com/bluedskim/javaDesignPatterns)

패턴 다이어그램

Iterators implement various traversal algorithms. Several iterator objects can traverse the same collection at the same time.

“하나의 집합Collection의 모든 요소를 모두 접근하는 방법은 여러가지가 있을 수 있다” (출처:https://refactoring.guru/design-patterns/iterator)

해결하려는 문제

  1. 집합collection의 각각 항목 모두를 접근할 수 있는 일관된 방법을 제공.

특징/용도

  1. behavioral design patterns의 하나
  2. iterator는 해당 집합의 실제 구현과는 무관하다(Information Hiding, Separation of concerns).

고려사항

  1. Java 1.2 부터 Iterable, Iterator 인터페이스가 포함되어 있으므로 직접 만들 필요가 없다.

클래스 다이어그램

Iterator 패턴(김동석)

소스

  1. target
    • MyIterable.java : 컨테이너가 구현해야하는 인터페이스
      1
      2
      3
      4
      5
      6
      7
      
      package net.dskim.desingpattern.iterator;
      
      import java.util.Iterator;
      
      public interface MyIterable extends Iterable<Object> {
          public Iterator<Object> reverseIterator();
      }
    • ArrayContainer.java : 배열을 가지고 있는 객체
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      
      package net.dskim.desingpattern.iterator;
      
      import java.util.Iterator;
      
      /***
       * 배열을 위한 컨테이너
       */
      public class ArrayContainer implements MyIterable {
      	Iterator<Object> arrayIterator;
      	Iterator<Object> reverseArrayIterator;
      
      	public ArrayContainer(Object[] array) {
      		arrayIterator = new ArrayIterator(array);
      		reverseArrayIterator = new ReverseArrayIterator(array);
      	}
      
      	@Override
      	public Iterator<Object> iterator() {
      		return arrayIterator;
      	}
      
      	@Override
      	public Iterator<Object> reverseIterator() {
      		return reverseArrayIterator;
      	}
      }
    • ArrayIterator.java : 배열학목을 순서대로 접근하기 위한 iterator
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      
      package net.dskim.desingpattern.iterator;
      
      import java.util.Iterator;
      import java.util.NoSuchElementException;
      
      import lombok.extern.slf4j.Slf4j;
      
      /***
       * 배열을 위한 iterator
       */
      @Slf4j
      public class ArrayIterator implements Iterator<Object>{
      	Object[] array;
      	int index = 0;
      
      	public ArrayIterator(Object[] array) {
      		this.array = array;
      	}
      
      	@Override
      	public boolean hasNext() {
      		return index <= array.length - 1;
      	}
      
      	@Override
      	public Object next() {
      		if(!hasNext()) throw new NoSuchElementException();
      		return array[index++];
      	}
      }
    • ReverseArrayIterator.java : 배열학목을 역순으로 접근하기 위한 iterator
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      
      package net.dskim.desingpattern.iterator;
      
      import java.util.Iterator;
      import java.util.NoSuchElementException;
      
      /***
       * 배열 index가 높은 항목에서 낮은 항목으로 탐색하는 iterator
       */
      public class ReverseArrayIterator implements Iterator<Object>{
      	Object[] reverseArray;
      	int nextIndex = 0;
      
      	public ReverseArrayIterator(Object[] originalArray) {
      		reverseArray = new Object[originalArray.length];
      		for(int reverseArrayIndex = 0 ; reverseArrayIndex < reverseArray.length ; reverseArrayIndex++){
      			reverseArray[reverseArrayIndex] = originalArray[originalArray.length - 1 - reverseArrayIndex];
      		}
      	}
      
      	@Override
      	public boolean hasNext() {
      		return nextIndex <= reverseArray.length - 1;
      	}
      
      	@Override
      	public Object next() {
      		if(!hasNext()) throw new NoSuchElementException();
      		return reverseArray[nextIndex++];
      	}
      }
  2. client : IteratorTest.java
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    
    package net.dskim.desingpattern.iterator;
    
    import static org.junit.jupiter.api.Assertions.assertEquals;
    
    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.List;
    
    import org.junit.jupiter.api.Test;
    
    import lombok.extern.slf4j.Slf4j;
    
    @Slf4j
    public class IteratorTest {
    
    	/**
    	 * java.util.List의 iterator테스트
    	 */
    	@Test
    	void listIteratorTest() {
    		List<String> names = new ArrayList<String>();
    		names.add("Ajay");
    		names.add("Vijay");
    		names.add("Martin");
    		names.add("Racheal");
    		names.add("Kim");
    
    		Iterator<String> namesIterator = names.iterator();
    		int i = 0;
    		while (namesIterator.hasNext()) {
    			assertEquals(names.get(i++), namesIterator.next());
    		}
    	}
    
    	@Test
    	void arrayIteratorTest() {
    		String[] names = {
    			"Ajay"
    			,"Vijay"
    			,"Martin"
    			,"Racheal"
    			,"Kim"
    		};
    		
    		MyIterable arrayContainer = new ArrayContainer(names);
    
    		int i = 0;
    		Iterator<Object> arrayIterator = arrayContainer.iterator();
    		while (arrayIterator.hasNext()) {
    			assertEquals(names[i++], arrayIterator.next());
    		}
    
    		i = 0;
    		Iterator<Object> reverseArrayIterator = arrayContainer.reverseIterator();
    		while (reverseArrayIterator.hasNext()) {
    			assertEquals(names[names.length - (++i)], reverseArrayIterator.next());
    		}
    	}	
    }

참고