[루비 사용자 가이드] 접근자(Accessors)

루비/레일스 프로그래밍/루비 사용자 가이드 2009.02.06 10:44

접근자(Accessor)란 무엇인가?

예전에 인스턴스 변수에 대해 간략히 살펴보았지만, 자세히 다루지는 않았습니다. 객체의 인스턴스 변수는 객체의 어트리뷰트입니다. 즉, 인스턴스 변수는 어떤 객체를 동일한 클래스에 속하는 다른 객체와 구분하게 하는 것 중 하나입니다. 이러한 어트리뷰트를 읽고 쓸 수 있는 것은 매우 중요합니다. 그러한 작업(어트리뷰트 읽고 쓰기)에는
어트리뷰트 접근자(attribute accessors)라는 메소드가 필요합니다. 잠시 후에 반드시 접근자 메소드를 사용자가 작성해야 하는 것은 아님을 보게 되겠지만, 지금은 모든 작업을 직접 해 봅시다. 두 가지 종류의 접근자는 쓰기접근자(writers)읽기접근자(eaders)입니다.

ruby> class Fruit
    |   def set_kind(k)  # a writer
    |     @kind = k
    |   end
    |   def get_kind     # a reader
    |     @kind
    |   end
    | end
   nil
ruby> f1 = Fruit.new
   #<Fruit:0xfd7e7c8c>
ruby> f1.set_kind("peach")  # use the writer
   "peach"
ruby> f1.get_kind           # use the reader
   "peach"
ruby> f1                    # inspect the object
   #<Fruit:0xfd7e7c8c @kind="peach">

아주 단순하지요! 우리가 보고 있는 과일의 종류가 어떤 것인지 정보를 저장하고, 읽어올 수 있습니다. 하지만, 여기서 사용한 메소드 이름은 너무 복잡합니다. 아래와 같이 쓰는 것이 더 간단하면서 더 일반적일 겁니다.

ruby> class Fruit
    |   def kind=(k)
    |     @kind = k
    |   end
    |   def kind
    |     @kind
    |   end
    | end
   nil
ruby> f2 = Fruit.new
   #<Fruit:0xfd7e7c8c>
ruby> f2.kind = "banana"
   "banana"
ruby> f2.kind
   "banana"

inspect 메소드

잠깐 딴 이야기를 해 봅시다. 객체를 직접 들여다 볼 때, #<anObject:0x83678>처럼 암호같은 결과를 보게 됩니다. 이것은 단지 기본값으로 설정되어 있는 기능입니다. 여러분은 이 기능을 마음대로 바꿀 수 있습니다. 필요한 것은 inspect라 불리는 메소드를 정의하는 것 하나 뿐입니다. 이 메소드는 객체의 인스턴스 변수 전체(혹은 일부)의 상태를 포함하는 객체를 잘 설명할 수 있는 스트링을 반환해야 합니다.

ruby> class Fruit
    |   def inspect
    |     "a fruit of the #{@kind} variety"
    |   end
    | end
   nil
ruby> f2
   "a fruit of the banana variety"

앞의 메소드와 관련된 또 하나의 메소드는 to_s (스트링으로 변환하기)입니다. to_s는 객체를 출력할 때 쓰입니다. 일반적으로 inspect는 프로그램 작성과 디버깅을 위한 도구이고, to_s는 프로그램의 출력을 위한 방법입니다. eval.rbinspect를 결과 값을 표시하기 위해 사용합니다. p 메소드를 사용하면, 프로그램에서도 디버깅 출력을 얻을 수 있습니다.

# These two lines are equivalent:
p anObject
puts anObject.inspect

접근자를 만드는 쉬운 방법

많은 인스턴스 변수에 대해 접근자 메소드가 필요하기 때문에, 루비는 표준적인 형태로 접근자를 작성하는 쉬운 방법을 제공합니다.

Shortcut Effect
attr_reader :v def v; @v; end
attr_writer :v def v=(value); @v=value; end
attr_accessor :v attr_reader :v; attr_writer :v
attr_accessor :v, :w attr_accessor :v; attr_accessor :w

위 기능을 사용해 과일의 신선도를 추가해 봅시다. 우선, 자동으로 읽기접근자와 쓰기접근자를 작성하도록 할 수 있습니다. 이제 새로 추가된 정보를 inspect에도 넣어줍시다.

ruby> class Fruit
    |   attr_accessor :condition
    |   def inspect
    |     "a #{@condition} #{@kind}"
    |   end
    | end
   nil
ruby> f2.condition = "ripe"
   "ripe"
ruby> f2
   "a ripe banana"

과일로 장난하기

아무도 과일을 먹지 않으면, 우리가 만든 과일이 시간이 지남에 따른 변화를 가지도록 할 수 있습니다.

ruby> class Fruit
    |   def time_passes
    |     @condition = "rotting"
    |   end
    | end
   nil
ruby> f2
   "a ripe banana"
ruby> f2.time_passes
   "rotting"
ruby> f2
   "a rotting banana"

하지만, 이렇게 클래스를 변경하다 보니, 작은 문제가 발생하게 되었습니다. 만약 우리가 새로 과일을 만들게 되면 어떤 일이 벌어질까요? 인스턴스 변수는 값이 대입되기 전까지 존재하지 않는 다는 것을 기억에서 떠올려보십시오.

ruby> f3 = Fruit.new
ERR: failed to convert nil into String

여기서 오류가 발생한 부분은 inspect 메소드입니다. 이 오류는 정당한 것입니다. 우리는 어떤 과일의 종류와 상태를 알려달라고 요청을 했습니다. 하지만, 아직 f3 객체는 어떤 어트리뷰트에도 값을 대입하지 않은 상태입니다.
원한다면 inspect 메소드에서 defined? 메소드를 사용해서 인스턴스 변수가 정의되어 있는지를 확인한 후, 정의된 인스턴스 변수만 보고하도록 할 수도 있을 겁니다. 하지만 그런식으로 처리하는 것은 그리 유용하지 않을 겁니다. 모든 과일은 종류와 상태를 어트리뷰트로 가지고 있기 때문에, 우리는 항상 그 두 어트리뷰트가 정의되어 있다는 것을 확실히 할 수 있어야 할 것입니다. 그게 바로 다음에 다룰 내용입니다.

신고
크리에이티브 커먼즈 라이선스
Creative Commons License
Trackback 0 : Comment 0

티스토리 툴바