[Design Pattern] 반복자 패턴
반복자 패턴이란?
객체를 저장하는 방식은 보여주지 않으면서도 객체들에게 일일이 접근한 수 있게 해주는 방법.(OOP의 캡슐화)
알게모르게 사용하는 방법인데, C++에서의 stl의 iterator(vector, map, list)
일반적인 Array(배열)에서는 index로 배열을 참조하기 때문에 의미가 없지만 LinkedList라면 다릅니다.
사용하는 이유
- 집합체 클래스의 응집도를 높여준다.
- 내부에서 어떤 식으로 처리되는지 client가 일일히 알 필요 없이, 모든 항목에 접근 할 수 있게 해준다. (캡슐화)
- 집합체 인터페이스 등의 구현이 간단해진다.
문제점&주의사항
- 알고리즘 구현 부분에 따라 캡슐화에 위배할 수 도 있다.
- 힙 메모리를 삭제하지 않아 오류가 발생할 수 있다.
사용법
(이미지 출처 : https://ko.wikipedia.org/wiki/%EB%B0%98%EB%B3%B5%EC%9E%90_%ED%8C%A8%ED%84%B4 )
구조는 위의 class diagram과 같습니다.
구현 방법은 단순히 리스트 객체에 접근해서 새로운 내용을 삽입(또는 삭제) 하거나 반복하는 내용을 반복자 객체에 정의하는 것으로 구현할 수 있습니다.
샘플 코드
#include <iostream>
#include <vector>
// Iterator 인터페이스
class Iterator{
public:
virtual ~Iterator() {}
virtual void First() = 0;
virtual void Next() = 0;
virtual bool IsDone() const = 0;
virtual int CurrentItem() const = 0;
};
// Concrete Iterator 클래스
class ConcreteIterator : public Iterator {
private:
std::vector<int> collection_;
int current_index_ = 0;
public:
ConcreteIterator(const std::vector<int>& collection) : collection_(collection) {}
void First() override {
current_index_ = 0;
}
void Next() override {
current_index_++;
}
bool IsDone() const override {
return current_index_ >= collection_.size();
}
int CurrentItem() const override {
if (IsDone()) {
return -1; // 또는 예외 처리
}
return collection_[current_index_];
}
};
// Aggregate 인터페이스
class Aggregate {
public:
virtual ~Aggregate() {}
virtual Iterator* CreateIterator() = 0;
};
// Concrete Aggregate 클래스
class ConcreteAggregate : public Aggregate {
private:
std::vector<int> collection_;
public:
ConcreteAggregate(const std::vector<int>& collection) : collection_(collection) {}
Iterator* CreateIterator() override {
return new ConcreteIterator(collection_);
}
};
int main() {
std::vector<int> numbers = {1, 2, 3, 4, 5};
ConcreteAggregate aggregate(numbers);
Iterator* iterator = aggregate.CreateIterator();
for (iterator->First(); !iterator->IsDone(); iterator->Next()) {
std::cout << iterator->CurrentItem() << " ";
}
std::cout << std::endl;
delete iterator; // 중요: 동적 할당된 메모리 해제
return 0;
}