Delegator 클래스
Delegator 클래스
어떤 객체에 메서드 호출을 "넘겨주는"(delegate) 일은 의외로 자주 하게 돼요. 이 라이브러리는 그 위임을 설정하는 세 가지 방법을 제공해요.
가장 쓰기 쉬운 건 SimpleDelegator예요. 생성자에 객체를 넘기면 그 객체가 지원하는 모든 메서드가 위임되어요. 이 대상 객체는 나중에 바꿀 수도 있어요.
한 단계 더 나아가, 최상위 DelegateClass 메서드는 클래스 상속을 통해 손쉽게 위임을 설정하게 해 줘요. 이 방식은 훨씬 유연해서 아마 이 라이브러리에서 가장 흔하게 쓰일 거예요.
마지막으로, 위임 체계를 완전히 제어해야 한다면 추상 클래스 Delegator를 상속받아 필요에 맞게 커스터마이즈할 수 있어요. (이런 제어가 필요할 때는 표준 라이브러리의 Forwardable도 한 번 봐보세요. 여러분 요구에 더 맞을 수도 있어요.)
SimpleDelegator의 구현이 Delegator 사용법의 좋은 예시예요:
require 'delegate'
class SimpleDelegator < Delegator
def __getobj__
@delegate_sd_obj # return object we are delegating to, required
end
def __setobj__(obj)
@delegate_sd_obj = obj # change delegation object,
# a feature we're providing
end
end
주의
RDoc은 위임된 메서드를 감지하지 못한다는 점 알아두세요.
상수
VERSION— 버전 문자열
클래스 메서드
-
new(obj)— 메서드 호출을 위임할 obj를 받아요. obj가 지원하는 모든 메서드가 위임돼요.# File lib/delegate.rb, line 76 def initialize(obj) __setobj__(obj) end
인스턴스 메서드
-
!()—!를__getobj__로 위임해요.# File lib/delegate.rb, line 181 def ! !__getobj__ end -
!=(obj) → true or false— 두 객체가 값이 같지 않다고 여겨질 때 true를 돌려줘요.# File lib/delegate.rb, line 165 def !=(obj) return false if obj.equal?(self) __getobj__ != obj end -
==(obj) → true or false— 두 객체가 값이 같다고 여겨질 때 true를 돌려줘요.# File lib/delegate.rb, line 157 def ==(obj) return true if obj.equal?(self) self.__getobj__ == obj end -
__getobj__()— 서브클래스가 반드시 재정의해야 하는 메서드예요. 메서드 호출이 위임되고 있는 객체를 돌려줘야 해요.# File lib/delegate.rb, line 189 def __getobj__ __raise__ ::NotImplementedError, "need to define '__getobj__'" end -
__setobj__(obj)— 서브클래스가 반드시 재정의해야 하는 메서드예요. 위임 대상 객체를 obj로 바꿔요.# File lib/delegate.rb, line 197 def __setobj__(obj) __raise__ ::NotImplementedError, "need to define '__setobj__'" end -
eql?(obj) → true or false— 두 객체가 같은 값으로 여겨질 때 true를 돌려줘요.# File lib/delegate.rb, line 173 def eql?(obj) return true if obj.equal?(self) obj.eql?(__getobj__) end -
freeze()—__getobj__가 돌려주는 객체와 자기 자신을 모두 동결해요.# File lib/delegate.rb, line 238 def freeze __getobj__.freeze super() end -
marshal_dump()—__getobj__가 돌려주는 객체의 직렬화를 지원해요.# File lib/delegate.rb, line 204 def marshal_dump ivars = instance_variables.reject {|var| /\A@delegate_/ =~ var} [ :__v2__, ivars, ivars.map {|var| instance_variable_get(var)}, __getobj__ ] end -
marshal_load(data)— 직렬화된 객체에서 위임을 다시 설정해요.# File lib/delegate.rb, line 216 def marshal_load(data) version, vars, values, obj = data if version == :__v2__ vars.each_with_index {|var, i| instance_variable_set(var, values[i])} __setobj__(obj) else __setobj__(data) end end -
method_missing(m, *args, &block)— 받은 메서드 호출을 위임 객체로 전달해요. 위임 대상이 그 메서드를 지원하거나Kernel에 정의돼 있으면 처리하고, 그렇지 않으면super로 넘겨요.# File lib/delegate.rb, line 83 def method_missing(m, *args, &block) r = true target = self.__getobj__ {r = false} if r && target_respond_to?(target, m, false) target.__send__(m, *args, &block) elsif ::Kernel.method_defined?(m) || ::Kernel.private_method_defined?(m) ::Kernel.instance_method(m).bind_call(self, *args, &block) else super(m, *args, &block) end
end
내부적으로 `BasicObject#method_missing`을 호출해요.
- `methods(all=true)` — 이 델리게이트 객체에서 쓸 수 있는 메서드를, 이 객체의 메서드와 `__getobj__` 메서드의 합집합으로 돌려줘요.
```ruby
# File lib/delegate.rb, line 132
def methods(all=true)
__getobj__.methods(all) | super
end
-
protected_methods(all=true)— 보호 메서드들을__getobj__메서드와의 합집합으로 돌려줘요.# File lib/delegate.rb, line 148 def protected_methods(all=true) __getobj__.protected_methods(all) | super end -
public_methods(all=true)— 공개 메서드들을__getobj__메서드와의 합집합으로 돌려줘요.# File lib/delegate.rb, line 140 def public_methods(all=true) __getobj__.public_methods(all) | super end -
raise()—Delegator에raise메서드 호출을 위임할 객체가 없을 때는__raise__를 사용해요.__raise__의 별칭이기도 해요.# File lib/delegate.rb, line 67 -
respond_to_missing?(m, include_private)—__getobj__를 통해 호출을 전달해서, 이 위임 객체가 제공하는 메서드인지 확인해요.# File lib/delegate.rb, line 100 def respond_to_missing?(m, include_private) r = true target = self.__getobj__ {r = false} r &&= target_respond_to?(target, m, include_private) if r && include_private && !target_respond_to?(target, m, false) warn "delegator does not forward private method \##{m}", uplevel: 3 return false end r end
private 인스턴스 메서드
-
target_respond_to?(target, m, include_private)—BasicObject인스턴스를 처리해요. 대상이Object면respond_to?로, 아니면Kernel#respond_to?를 바인딩해서 확인해요.# File lib/delegate.rb, line 115 def target_respond_to?(target, m, include_private) case target when Object target.respond_to?(m, include_private) else if KERNEL_RESPOND_TO.bind_call(target, :respond_to?) target.respond_to?(m, include_private) else KERNEL_RESPOND_TO.bind_call(target, m, include_private) end end
end
> 출처: [Ruby 4.0 API - Delegator](https://docs.ruby-lang.org/en/4.0/Delegator.html)
## 더 알아보기
- [SimpleDelegator](https://docs.ruby-lang.org/en/4.0/SimpleDelegator.html) — 가장 쓰기 쉬운 위임 객체
- [Forwardable](https://docs.ruby-lang.org/en/4.0/Forwardable.html) — 위임 체계를 완전히 제어해야 할 때 대안이 되는 표준 라이브러리