Rails Insights
```html

루비에서의 디자인 패턴: 이터레이터 구현하기

디자인 패턴은 소프트웨어 개발에서 반복적으로 발생하는 문제를 해결하기 위한 일반적인 솔루션입니다. 루비(Ruby) 같은 객체 지향 프로그래밍 언어에서는 이러한 패턴을 활용하여 코드의 재사용성과 가독성을 높일 수 있습니다. 이번 글에서는 이터레이터(Iterator) 패턴에 대해 알아보고, 이를 루비에서 어떻게 구현할 수 있는지 살펴보겠습니다.

이터레이터 패턴이란?

이터레이터 패턴은 컬렉션 객체의 내부 구조를 노출하지 않고도 그 컬렉션의 요소를 순차적으로 접근할 수 있게 해주는 디자인 패턴입니다. 이 패턴은 컬렉션의 요소를 반복(iterate)하는 방법을 제공하며, 다양한 데이터 구조에서 요소를 일관되게 탐색할 수 있도록 도와줍니다.

이터레이터 패턴의 장점

  • 컬렉션의 내부 구조를 숨길 수 있어 캡슐화를 유지할 수 있다.
  • 다양한 데이터 구조에 대해 동일한 인터페이스를 제공하여 코드의 일관성을 높일 수 있다.
  • 컬렉션의 요소를 쉽게 순회할 수 있어 코드의 가독성이 향상된다.

루비에서 이터레이터 구현하기

이제 루비에서 이터레이터 패턴을 어떻게 구현할 수 있는지 살펴보겠습니다. 먼저, 간단한 이터레이터 클래스를 정의해 보겠습니다.

이터레이터 클래스 정의

이터레이터 클래스를 정의하기 위해서는 먼저 컬렉션을 저장할 클래스와 이터레이터 클래스를 만들어야 합니다.

class MyCollection
  def initialize
    @items = []
  end

  def add(item)
    @items << item
  end

  def each
    @items.each { |item| yield(item) }
  end
end

위의 코드에서 MyCollection 클래스는 아이템을 저장하는 배열인 @items를 가지고 있습니다. add 메서드는 아이템을 추가하는 역할을 하며, each 메서드는 블록을 사용하여 각 아이템을 순회합니다.

이터레이터 사용하기

이제 MyCollection 클래스를 사용하여 이터레이터를 테스트해 보겠습니다.

collection = MyCollection.new
collection.add("사과")
collection.add("바나나")
collection.add("체리")

collection.each do |item|
  puts item
end

위의 코드는 MyCollection 클래스의 인스턴스를 생성하고, 과일 이름을 추가한 후, each 메서드를 사용하여 모든 과일 이름을 출력합니다. 이처럼 이터레이터를 사용하면 컬렉션의 요소를 간편하게 순회할 수 있습니다.

더 발전된 이터레이터 구현

기본적인 이터레이터를 구현한 후, 이제는 좀 더 발전된 이터레이터를 만들어 보겠습니다. 예를 들어, 이터레이터에 상태를 추가하여 다음 요소로 이동하거나 이전 요소로 돌아갈 수 있도록 구현할 수 있습니다.

상태를 가진 이터레이터

class AdvancedIterator
  def initialize(collection)
    @collection = collection
    @current_index = 0
  end

  def next
    return nil if @current_index >= @collection.size
    item = @collection[@current_index]
    @current_index += 1
    item
  end

  def has_next?
    @current_index < @collection.size
  end

  def reset
    @current_index = 0
  end
end

위의 AdvancedIterator 클래스는 컬렉션을 순회할 수 있는 상태를 가지며, next, has_next?, reset 메서드를 통해 요소를 순회하고, 다음 요소가 있는지 확인하며, 이터레이터를 초기 상태로 되돌릴 수 있습니다.

상태를 가진 이터레이터 사용하기

이제 AdvancedIterator 클래스를 사용하여 이터레이터를 테스트해 보겠습니다.

collection = MyCollection.new
collection.add("사과")
collection.add("바나나")
collection.add("체리")

iterator = AdvancedIterator.new(collection)

while iterator.has_next?
  puts iterator.next
end

iterator.reset
puts "이터레이터를 초기화한 후:"
while iterator.has_next?
  puts iterator.next
end

위의 코드는 AdvancedIterator를 사용하여 컬렉션의 요소를 순회합니다. has_next? 메서드를 사용하여 다음 요소가 있는지 확인하고, next 메서드를 사용하여 요소를 가져옵니다. 이터레이터를 초기화한 후 다시 순회하는 것도 가능합니다.

루비의 내장 이터레이터

루비는 이미 다양한 내장 이터레이터를 제공합니다. 배열, 해시, 문자열 등 여러 컬렉션 객체에서 사용할 수 있는 이터레이터 메서드가 있습니다. 예를 들어, each, map, select와 같은 메서드를 통해 쉽게 요소를 순회하고 조작할 수 있습니다.

내장 이터레이터 예시

fruits = ["사과", "바나나", "체리"]

fruits.each do |fruit|
  puts fruit
end

squared_numbers = [1, 2, 3, 4].map { |n| n ** 2 }
puts squared_numbers.inspect

위의 코드에서 each 메서드를 사용하여 과일 목록을 출력하고, map 메서드를 사용하여 숫자의 제곱을 계산하여 새로운 배열을 생성합니다. 이처럼 루비의 내장 이터레이터를 사용하면 코드 작성이 훨씬 간편해집니다.

결론

이번 글에서는 루비에서 이터레이터 패턴을 구현하는 방법에 대해 알아보았습니다. 이터레이터 패턴은 컬렉션의 내부 구조를 숨기고, 요소를 순차적으로 접근할 수 있는 방법을 제공합니다. 기본적인 이터레이터 구현부터 발전된 이터레이터까지 살펴보았으며, 루비의 내장 이터레이터도 소개했습니다.

이러한 이터레이터 패턴을 활용하면 코드의 가독성과 재사용성을 높일 수 있으며, 다양한 데이터 구조를 일관되게 다룰 수 있습니다. 앞으로 루비를 사용할 때 이터레이터 패턴을 적극적으로 활용해 보시기 바랍니다.

```
Published: December 11, 2024

© 2024 RailsInsights. All rights reserved.