[행동 패턴] 반복자 패턴 - Iterator
반복자 패턴은 리스트와 같은 집합 객체들이 내부 표현부를 노출하지 않고 어떤 집합 객체에 속한 원소들을 순차적으로 접근하는 패턴입니다.
(C++ 에서는 기본적으로 STL 컨테이너를 순회하는 iterator를 기본으로 제공합니다.)
목적
내부 표현부를 노출하지 않고 어떤 집합 객체의 속한 원소들을 순차적으로 접근할 수 있는 방법을 제공합니다.
활용
- 정의한 방법과 다른 방법으로 원소들을 순회하고자 할 때
- 동일한 리스트에 대해서 하나 이상의 순회방법을 정의하고 싶을 때
- 객체 내부 표현 방식을 모르고도 집합 객체의 원소에 접근하고 싶을 때
- 집합 객체를 순회하는 당양한 방법을 지원하고 싶을 때
- 서로 다른 집합 객체 구조에 대해서도 동일한 방법으로 순회하고 싶을 때
장점
- 집합 객체의 다양한 순회 방법을 제공합니다.
- 집합 객체에 따라 하나 이상의 순회 방법이 제공됩니다.
단점
- 순회 알고리즘 구현 부분에 따라서 캡슐화 전략을 위배할 수 도 있습니다.
(구현 부분에 주의가 필요합니다.)
- 사용자가 직접 반복자를 삭제하는 책임을 가져야 합니다.
(힙 메모리를 삭제하지 않아 오류가 발생할 수 있습니다.)
구현
리스트 객체에 접근해서 새로운 내용을 삽입 / 삭제하거나 순회하는 내용을 반복자 객체에 정의하는 것으로 구현될 수 있습니다.
우선 List 클래스를 구현합니다.
1 2 3 4 5 6 7 8 9 10 11 | template<class Item> class List { public : List(long size = DEFAULT_LIST_CAPACITY); long Count(); Item& Get(long index) const; //.... 이상의 자세 구현은 책의 부록이므로 삭제..../ }; | cs |
Iterator의 인터페이스를 구현합니다.
1 2 3 4 5 6 7 8 9 10 11 12 | template<class Item> class Iterator { public : virtual void First() = 0; virtual void Next() = 0; virtual bool IsDone() const = 0; virtual Item CurrentItem() const = 0; protected : Iterator(); }; | cs |
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 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 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | //-- 정방향 반복자 template<class Item> class ListIterator : public Iterator<Item> { public: ListIterator(const List<Item>* aList); virtual void First() override; virtual void Next() override; virtual bool IsDone() const override; virtual Item CurrentItem() const override; private : const List<Item>* _list; long _current; }; template<class Item> ListIterator<Item>::ListIterator (const List<Item>* aList) : _list(aList) , _current(0) {} template<class Item> void ListIterator<Item>::First() { _current = 0; } template<class Item> void ListIterator<Item>::Next() { _current++; } template<class Item> bool ListIterator<Item>::IsDone() const { return _current >= _list->Count(); } template<class Item> Item ListIterator<Item>::CurrentItem() const { if (IsDone()) { throw IteratorOutBounds; } return _list->Get(_current); } ///--- 역방향 반복자 template<class Item> class ReverseListIterator : public Iterator<Item> { public: ReverseListIterator(const List<Item>* aList); virtual void First() override; virtual void Next() override; virtual bool IsDone() const override; virtual Item CurrentItem() const override; private: const List<Item>* _list; long _current; }; template<class Item> ReverseListIterator<Item>::ReverseListIterator(const List<Item>* aList) { _list = aList; _current = _list->Count(); } template<class Item> void ReverseListIterator<Item>::First() { _current = _list->Count(); } template<class Item> void ReverseListIterator<Item>::Next() { _current--; } template<class Item> bool ReverseListIterator<Item>::IsDone() const { return _current <= 0; } template<class Item> Item ReverseListIterator<Item>::CurrentItem() const { if (IsDone()) { throw IteratorOutBounds; } return _list->Get(_current); } | cs |
이후 List를 제작하고 Iterator를 연산의 인자로 출력해봅니다.
1 2 3 4 5 6 7 | void PrintEmployees(Iterator<Employee*>& _data) { for (_data.First(); !_data.IsDone(); _data.Next()) { _data.CurrentItem()->Print(); } } | cs |
1 2 3 4 5 6 7 8 9 10 11 | void main() { List<Employee*>* employees; ListIterator<Employee*> foward(employees); ReverseListIterator<Employee*> backward(employees); PrintEmployees(foward); cout << "----------" << endl; PrintEmployees(backward); } | cs |
[결과]
이제 구현 표준을 벗어나는 상황을 방지하면서, List를 변형해봅니다.
바람직한 방법으로는 List 인터페이스를 표준화한 abstrctList 클래스를 만드는 것이 바람직합니다. 그리고 난후에 다양한 구현을 abstrctList 의 서브클래스로 만듭니다.
1 2 3 4 5 6 7 | template <class Item> class AbstractList { public : virtual Iterator<Item*> CreateIterator() const = 0; //.. }; | cs |
[후기]
책에 나와 있지도 않고 누락된 코드는 작성자가 직접 작성해야 했습니다.ㅠ_ㅠ..
혹시나 책을 사시는 분들은 참고해주세요..
[참고] - GOF의 디자인 패턴
'프로그래밍 관련 > 디자인 패턴' 카테고리의 다른 글
[행동 패턴] 관찰자 패턴 - Observer (1) | 2016.12.22 |
---|---|
[행동 패턴] 명령 패턴 - Command (0) | 2016.09.20 |
[생성 패턴] 추상 팩토리 패턴 - Abstract Factory (0) | 2016.07.28 |
디자인 패턴을 공부해보자! (0) | 2016.07.28 |