이터레이터 패턴
Coddy C 여정의 Object Oriented Programming 섹션에 포함된 레슨 — 61개 중 56번째.
반복자 패턴(Iterator pattern)은 컬렉션의 내부 구조를 노출하지 않고 요소들에 순차적으로 접근할 수 있는 방법을 제공합니다. 사용자에게 배열에 직접 접근하게 하는 대신, 데이터를 한 번에 하나씩 순회하는 방법을 알고 있는 객체를 제공합니다.
반복자(iterator)는 일반적으로 두 가지 정보가 필요합니다: 컬렉션에 대한 참조와 현재 위치입니다. C 언어에서는 이 상태를 유지하기 위해 구조체(struct)를 생성합니다:
typedef struct {
int* data; // 배열을 가리키는 포인터
int size; // 전체 요소의 개수
int current; // 현재 위치
} IntIterator;이 이터레이터는 두 가지 주요 함수를 제공합니다. has_next()는 읽을 요소가 더 있는지 확인하며, next()는 현재 요소를 반환하고 위치를 이동시킵니다:
int has_next(IntIterator* it) {
return it->current < it->size;
}
int next(IntIterator* it) {
return it->data[it->current++];
}이터레이터를 사용하면 코드가 깔끔해 보이고 배열의 세부 사항을 숨길 수 있습니다:
IntIterator it = create_iterator(numbers, 5);
while (has_next(&it)) {
printf("%d\n", next(&it));
}호출자는 numbers가 배열이라거나 인덱싱이 어떻게 작동하는지 알 필요가 전혀 없습니다. 이러한 추상화는 나중에 이터레이터를 사용하는 코드를 변경하지 않고도 기본 데이터 구조를 — 예를 들어, 배열에서 연결 리스트로 — 쉽게 변경할 수 있게 해줍니다.
챌린지
쉬움정수 배열의 내부 구조를 노출하지 않고 컬렉션을 순회할 수 있는 깔끔한 추상화 도구인 NumberList 반복자(iterator)를 만들어 봅시다.
코드는 다음 세 개의 파일로 구성합니다:
iterator.h: 정수 배열에 대한 포인터, 컬렉션의 전체 크기, 그리고 현재 위치를 저장하는IntIterator구조체를 정의합니다. 세 가지 함수를 선언하세요:create_iterator(배열 포인터와 크기를 받아 초기화된 반복자를 반환),has_next(남은 요소가 있는지 확인),next(현재 요소를 반환하고 위치를 이동). 인클루드 가드(include guards)를 잊지 마세요!iterator.c: 반복자 함수들을 구현합니다.create_iterator함수는 현재 위치가 0으로 설정된IntIterator를 값으로 반환해야 합니다.has_next함수는 읽을 요소가 더 있으면 1을, 그렇지 않으면 0을 반환합니다.next함수는 현재 위치의 요소를 반환한 후 위치를 증가시킵니다.main.c: 요소의 개수를 읽은 다음, 각 정수 값을 배열에 읽어 들입니다. 이 배열에 대한 반복자를 생성한 후,has_next와next를 사용하는 while 루프를 통해 각 요소를 순회하며 한 줄에 하나씩 출력합니다.
프로그램은 다음을 입력받습니다:
- 배열의 요소 개수
- 각 정수 값 (각각 별도의 줄에 입력됨)
반복자 패턴을 사용하여 모든 요소를 출력하세요. 순회 루프 내에서 배열 인덱스에 직접 접근해서는 안 됩니다!
입력이 4이고, 이어서 10, 20, 30, 40일 때의 출력 예시:
10
20
30
40입력이 3이고, 이어서 -5, 0, 100일 때의 출력 예시:
-5
0
100입력이 1이고, 이어서 42일 때의 출력 예시:
42반복자는 데이터가 저장되는 방식을 숨깁니다. 메인 루프는 배열 인덱스나 메모리 레이아웃에 대해 전혀 알 필요 없이 단순히 "더 있나요?"와 "다음 요소를 주세요"라고 요청하기만 하면 됩니다.
치트 시트
반복자 패턴(Iterator pattern)은 컬렉션의 내부 구조를 노출하지 않고 요소들에 순차적으로 접근할 수 있는 방법을 제공합니다.
반복자 구조체는 컬렉션 참조, 크기 및 현재 위치를 보유합니다:
typedef struct {
int* data; // pointer to the array
int size; // total number of elements
int current; // current position
} IntIterator;반복자는 두 가지 주요 함수를 노출합니다:
int has_next(IntIterator* it) {
return it->current < it->size;
}
int next(IntIterator* it) {
return it->data[it->current++];
}반복자를 사용하면 배열의 구현 세부 사항을 숨길 수 있습니다:
IntIterator it = create_iterator(numbers, 5);
while (has_next(&it)) {
printf("%d\n", next(&it));
}이러한 추상화를 통해 클라이언트 코드를 수정하지 않고도 내부 데이터 구조를 변경할 수 있습니다.
직접 해보기
#include <stdio.h>
#include "iterator.h"
int main() {
int n;
scanf("%d", &n);
int arr[n];
// TODO: n개의 정수 값을 배열로 읽어오기
for (int i = 0; i < n; i++) {
scanf("%d", &arr[i]);
}
// TODO: 배열을 위한 iterator 생성하기
// TODO: 순회하기 위해 has_next와 next를 사용하는 while 루프 사용하기
// 그리고 각 요소를 개별 줄에 출력하기
// 순회 루프에서 직접적인 배열 인덱싱을 사용하지 마세요!
return 0;
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.