루비 프라이빗 클래스 메소드

24 1 월 2016

루비 프로그래밍 언어에서 정의 된 메서드는 인스턴스 메서드와 클래스 메서드의 두 가지 변형으로 제공됩니다. 인스턴스 메서드는 개체를 초기화한 후 인스턴스를 만들어 사용할 수 있습니다. 반면에 클래스 메서드는 정의된 클래스의 인스턴스를 만들지 않고도 사용할 수 있습니다.

루비 방법은 가시성이 다를 수 있습니다. 공용 메서드는 모든 컨텍스트에서 사용할 수 있지만 개인 메서드의 가용성은 클래스 및 해당 하위 인스턴스에서 제한됩니다. 보호되는 세 번째 가시성 범위는 개인 메서드와 유사하게 작동하지만 보호 된 메서드는 동일한 클래스의 다른 인스턴스에서 호출 할 수 있습니다.

빠른 리프레셔의 경우 공용 및 개인 인스턴스 메서드는 다음과 같습니다:

class Dog def do_trick bark end private def bark puts 'woof woof' endend

공용 메서드가 호출될 때:

> dog = Dog.new> dog.do_trick# => woof woof

그리고 개인 방법:

> dog = Dog.new> dog.bark# => NoMethodError: private method `bark' called for <Dog>

개인 클래스 메서드는 개인 인스턴스 메서드만큼 일반적이지 않을 수 있지만 여전히 해당 위치가 있습니다. 예를 들어,클래스 메서드는 함수를 완료하기 위해 내부 도우미 메서드가 필요할 수 있습니다. 이유가 무엇이든,개인 클래스 메소드를 정의하는 것은 가치가 있지만 항상 직관적 인 것은 아닙니다.

이 예제Dog클래스는 다른 공용 클래스 메서드 내에서 사용할tricks목록을 유지 관리해야 합니다. 이 목록은Dog클래스 외부의 호출자가 액세스할 수 없습니다.

잘못된 방법

개인tricks메서드를 작성할 때의 첫 번째 패스는 다음과 같을 수 있습니다:

class Dog private def self.tricks endend

그러나tricks방법의 가시성을 테스트 할 때:

> Dog.tricks# => 

어 오,개인 메소드가 호출되었음을 나타내는 오류가 발생하지 않았습니다.이 메소드는 완전히 공개됩니다.

왜?

위의 코드가 개인 메서드를 생성하지 않은 이유는 루비의 객체 계층 구조,내부 클래스 간의 상호 작용,해당 클래스의 인스턴스 및 고유 클래스와 관련이 있습니다. 루비의 객체가 서로 어떻게 작동하는지에 대한 자세한 내용은 이전 게시물에서 찾을 수 있습니다.

클래스에서 메서드를 정의할 때self.메서드 선언에 의해 도입된 기본 컨텍스트와 컨텍스트는 서로 다릅니다.

전용 메서드 범위는Dog클래스에 정의되고self컨텍스트 내에서 정의된 메서드 간의 컨텍스트 변경을 처리하지 않으므로 위의 방법으로 사용할 수 없습니다.

그래서 대안은 무엇입니까?

클래스<<자체

객체에서 클래스 메서드를 정의하는 다른 방법 중 하나는class << self구문을 사용하는 것입니다. 이 구문은 제공된 인수에 대한 고유 클래스를 엽니 다. 이 예에서selfDog클래스 내에서Dog's고유 클래스가 열립니다.

class Dog class << self private def tricks end endend

한 가지 주목할 점은 이와 같은 메소드를 정의 할 때 선언이def self.tricks에서 단순히def tricks로 변경되었다는 것입니다.

이제 사적 범위가 보존되고 예상되는 동작이 달성됩니다:

> Dog.tricks# => NoMethodError: private method `tricks' called for Dog:Class

모듈

루비의 모듈은 메서드와 상수의 모음입니다. 이러한 컬렉션은 캡슐화 도구 또는 이 경우 공용 및 개인 클래스 메서드를 정의하는 대안으로 사용할 수 있습니다.

클래스extends모듈,해당 모듈 내의 모든 메소드는*주제 클래스에 클래스 메소드가됩니다. 이 패턴을 사용하여Dog에서tricks메서드를 정의할 수 있습니다.

*주: 이는 모듈의def self.또는def Dog.메소드 정의가extended일 때 자동으로 같은 방식으로 클래스 메소드가되지 않는”일반적인 의미”로 정의 된 메소드에만 관련됩니다.

class Dog module ClassMethods private def tricks end end extend ClassMethodsend> Dog.tricks# => NoMethodError: private method `tricks' called for Dog:Class

이 방법의 장점은 가독성입니다. ClassMethods라는 모듈은Dog클래스에 의해 포함되고 캡슐화되어 원하는 모든 클래스 메소드에 대한 명확한 홈입니다.

private과 같은 가시성 수정자가 적절하게 동작하며 모듈 정의의 맨 아래에있는 간단한extend이 모두 함께 제공됩니다.세 번째 방법은 내장 방법Module#private_class_method을 사용하는 것입니다. 이 메서드의 목적은 기존 클래스 메서드의 가시성을 변경하는 것입니다.

다른 두 솔루션과 달리 이 솔루션에는 잘못된 솔루션과 다른 스타일의 메서드 정의가 필요하지 않습니다:

class Dog def self.tricks end private_class_method :tricksend> Dog.tricks# => NoMethodError: private method `tricks' called for Dog:Class

이 메서드는 클래스의 메서드 정의 중에 줄 지어있을 수도 있습니다:

class Dog private_class_method def self.tricks endend> Dog.tricks# => NoMethodError: private method `tricks' called for Dog:Class

단일 클래스 메서드가 개인이어야 하고 줄을 저장하는 것이 매우 중요한 경우 이 스타일을 적용할 수 있습니다; 그러나 확실히 가독성 수준을 희생합니다.

private_class_method의 주요 강점은 그 명료성이다. 다른 접근 방식과는 달리,이 방법은 특별한 모듈 정의 또는 메소드 정의 컨텍스트 전환을 필요로하지 않습니다.

추가 읽기

앞서 언급 한 솔루션은 작업을 완료 할 수 있지만 사물이 작동하는 이유에 대한 느린 질문에 대답하지 못할 수도 있습니다. 루비 고유 클래스에 대한 몇 가지 훌륭한 기사와 루비 메소드 디자인에 대한 마츠의 생각은 루비의 프라이빗 클래스 메소드 정의가 복잡한 이유에 대한보다 간결한 그림을 그리는 데 도움이 될 것입니다.

You might also like

답글 남기기

이메일 주소는 공개되지 않습니다.