Computer >> 컴퓨터 >  >> 프로그래밍 >> Ruby

루비(Ruby) private & protected 메서드: 메서드 가시성 완벽 이해하기

루비(Ruby)에서 private 메서드란 무엇일까요?

private 메서드는 오직 해당 메서드가 정의된 클래스 내부에서만 호출할 수 있는 메서드입니다. 이를 통해 개발자는 메서드에 대한 외부 접근을 효과적으로 제어할 수 있습니다.

루비 메서드의 가시성은 세 가지로 나눌 수 있습니다:

  • private
  • public (기본값)
  • protected

기본적으로 작성하는 모든 메서드는 public입니다. 즉, 누구든 어디서든 호출할 수 있죠.

하지만 메서드를 private 또는 protected로 지정하면 이 기본 동작을 바꿀 수 있습니다.

왜 이것이 유용할까요?

메서드를 더 쉽게 수정할 수 있기 때문입니다.

회사에서 여러 프로젝트에 사용될 코드 라이브러리를 작성한다고 상상해 보세요. 각 프로젝트는 여러분이 만든 클래스의 메서드를 호출하며 라이브러리를 활용할 겁니다.

그런데 새 버전을 출시하면서 public 메서드의 이름을 변경했다면 어떻게 될까요?

이 메서드를 사용 중인 모든 프로젝트에서 오류가 발생합니다!

꼭 기억하세요: public 메서드의 수를 줄일수록 클래스 내부 구조를 자유롭게 변경할 수 있는 여지가 커집니다.

그럼 코드 예제를 통해 자세히 살펴보겠습니다!

루비 private 메서드 이해하기

"private method called"라는 오류 메시지를 본 적이 있으신가요?

바로 이 오류입니다:

self.puts 123

# NoMethodError: private method `puts' called

이 오류는 private 메서드를 잘못된 방식으로 호출하려 했을 때 발생합니다.

private 메서드는 반드시 단독으로(수신자 없이) 호출해야 합니다.

예제:

puts 123

같은 메서드지만 위와 같이 호출해야 합니다.

private 메서드는 항상 self 컨텍스트 안에서 호출되기 때문입니다.

다시 말해, private 메서드는 다음 경우에만 사용할 수 있습니다:

  • 같은 클래스에 정의된 다른 메서드
  • 부모 클래스로부터 상속받은 메서드
  • 모듈을 통해 포함(include)한 메서드

즉, private 메서드를 정의한 클래스의 외부에서는 호출할 수 없습니다. 외부에서 호출하려면 명시적 수신자(explicit receiver)가 필요하기 때문입니다.

물론 예외는 있습니다. send 메서드를 사용하면 이 규칙을 우회할 수 있죠.

send(:puts, "apple")

그렇다면 private 메서드는 어떻게 정의할까요?

다음과 같이 정의합니다:

def bacon
  "private bacon"
end

private :bacon

여기서 private이라는 단어는 키워드가 아니라 Kernel 모듈에 정의된 하나의 메서드라는 점이 흥미롭습니다.

private 메서드는 어디에 배치할까?

클래스에 private 메서드가 여러 개 존재하는 것은 매우 자연스러운 일입니다. 그렇다면 이 메서드들을 어디에 배치해야 할까요?

권장 방식은 다음과 같습니다:

class Food
  def public_method
  end

  private

  def bacon
  end

  def orange
  end

  def coconut
  end
end

private 선언 이후에 등장하는 모든 인스턴스 메서드는 자동으로 private 메서드가 됩니다.

클래스 메서드를 private으로 만들고 싶다면 private_class_method :method_name을 사용하세요.

실무에서는 public 메서드를 먼저 모두 정의한 뒤, 클래스 마지막 부분에 private 메서드를 한데 모아 정의하는 패턴이 널리 사용됩니다.

public 메서드

public은 루비의 기본 메서드 가시성입니다.

예제:

def orange
  "Vitamin C"
end

orange 메서드를 가진 객체 food가 있다면 다음과 같이 호출할 수 있습니다:

food.orange

만약 어떤 메서드가 private 또는 protected로 지정되었다 해도, 다시 public으로 되돌릴 수 있습니다.

방법은 다음과 같습니다:

public :orange

protected 메서드란?

protected 메서드는 private 메서드만큼 흔하지 않습니다.

동작 방식은 private과 비슷하지만, 결정적인 차이가 하나 있습니다. 직접 호출뿐 아니라 객체를 통해서도 호출할 수 있다는 점입니다.

아래 예제를 private으로 작성하면 오류가 발생합니다:

class Food
  def initialize(name)
    @name = name
  end

  def ==(other)
    name == other.name
  end

  protected

  attr_reader :name
end

food = Food.new("chocolate")

puts food == food

오류가 발생하는 이유는 name이 private이 되어 other.name처럼 객체를 통해 접근할 수 없기 때문입니다.

하지만 protected를 사용하면 이 코드가 정상적으로 작동합니다!

private vs protected 메서드

정리하자면, protected는 메서드를 private처럼 숨기면서도 객체를 통해 메서드를 호출할 수 있게 허용한다는 점이 핵심 차이입니다.

  • private: name 형태로만 호출 가능
  • protected: object.name 형태로도 호출 가능

그렇다면 protected는 언제 사용해야 할까요?

동등 비교(==) 메서드처럼 아주 특수한 경우에만 사용하는 것이 좋습니다. 루비 공식 문서 역시 가능한 한 protected 대신 private을 사용할 것을 권장합니다.

또한 다음과 같은 주의 사항도 있습니다:

"protected 메서드는 인라인 캐시(inline cache)를 사용할 수 없어 속도가 느립니다."

실제로 궁금해서 간단한 벤치마크를 돌려 보았습니다:

public:    2813891.9 i/s
private:   2699273.8 i/s
protected: 2572122.0 i/s

결과적으로 protected는 public 대비 약 8.5%의 성능 차이를 보였습니다.

요약

지금까지 루비의 메서드 가시성인 public, private, protected 메서드에 대해 알아보았습니다. 이 세 가지는 루비의 키워드가 아니라 Module 클래스에 정의된 메서드 그 자체라는 점도 기억해 두세요.

이 글이 도움이 되셨다면 주변에 공유해 더 많은 분들이 이 주제를 이해할 수 있기를 바랍니다!

읽어주셔서 감사합니다 🙂