SimpleDelegator

SimpleDelegator

SimpleDelegatorDelegator의 구체적인 구현 클래스예요. 생성자에 넘긴 객체로 모든 지원되는 메서드 호출을 위임하고, 나중에 __setobj__로 위임 대상 객체를 바꿀 수도 있어요.

출처: Ruby 3.3 API

본문

먼저 데코레이터 패턴의 예를 볼게요.

class User
  def born_on
    Date.new(1989, 9, 10)
  end
end

require 'delegate'

class UserDecorator < SimpleDelegator
  def birth_year
    born_on.year
  end
end

decorated_user = UserDecorator.new(User.new)
decorated_user.birth_year  #=> 1989
decorated_user.__getobj__  #=> #<User: ...>

SimpleDelegatorDelegator의 하위 클래스라는 점을 활용해, 위임 대상 객체에 메서드를 호출하고 싶을 때 super를 쓸 수 있어요.

class SuperArray < SimpleDelegator
  def [](*args)
    super + 1
  end
end

SuperArray.new([1])[0]  #=> 2

다음은 위임 대상 객체를 언제든 바꿀 수 있다는 점을 활용한 간단한 예시예요.

class Stats
  def initialize
    @source = SimpleDelegator.new([])
  end

  def stats(records)
    @source.__setobj__(records)

    "Elements:  #{@source.size}\n" +
    " Non-Nil:  #{@source.compact.size}\n" +
    "  Unique:  #{@source.uniq.size}\n"
  end
end

s = Stats.new
puts s.stats(%w{James Edward Gray II})
puts
puts s.stats([1, 2, 3, nil, 4, 5, 1, 2])

출력은 다음과 같아요.

Elements:  4
 Non-Nil:  4
  Unique:  4

Elements:  8
 Non-Nil:  7
  Unique:  6

Public Instance Methods

__getobj__() { || ... }

현재 메서드 호출이 위임되는 객체를 돌려줘요.

__setobj__(obj)

위임 대상 객체를 obj로 바꿔요. SimpleDelegator의 메서드 자체가 바뀌는 건 아니니 주의해야 해요. 그래서 보통은 원래 위임 객체와 같은 타입의 객체로만 바꾸는 게 좋아요.

names = SimpleDelegator.new(%w{James Edward Gray II})
puts names[1]    # => Edward
names.__setobj__(%w{Gavin Sinclair})
puts names[1]    # => Sinclair