루비는 왜 개인 및 보호 방법을 모두 가지고 있습니까?


141

이 기사를 읽기 전에 Ruby의 액세스 제어가 다음과 같이 작동한다고 생각했습니다.

  • public- 모든 객체에 의해 액세스 할 수 있습니다 (예를 들어 Obj.new.public_method)
  • protected -객체 자체와 하위 클래스에서만 액세스 할 수 있습니다
  • private -protected와 동일하지만 메소드가 서브 클래스에 존재하지 않습니다.

그러나 것으로 보인다 protectedprivate같은 역할을 전화 할 수 없다는 사실을 제외하고 private명시 적 수신기 방법 (즉, self.protected_method작품,하지만 self.private_method하지 않습니다).

요점이 뭐야? 명시 적 리시버로 메소드를 호출하지 않으려는 시나리오는 언제입니까?


3
의 모든 인스턴스가의 다른 모든 인스턴스의 Object개인 메소드를 호출하도록 허용 된 경우 Object와 같은 것을 말할 수 있습니다 5.puts("hello world").
sepp2k

답변:


161

protected 메소드는 정의 클래스 또는 해당 서브 클래스의 모든 인스턴스에서 호출 할 수 있습니다.

private메소드는 호출 객체 내에서만 호출 할 수 있습니다. 다른 인스턴스의 프라이빗 메서드에 직접 액세스 할 수 없습니다.

다음은 간단한 실제 예입니다.

def compare_to(x)
 self.some_method <=> x.some_method
end

some_methodprivate여기 있을 수 없습니다 . 그것은해야합니다 protected당신이 명시 적으로 수신기를 지원하기 위해 필요하기 때문이다. 일반적인 내부 헬퍼 메소드는 일반적으로 private이와 같이 호출 할 필요가 없기 때문에 일반적 일 수 있습니다 .

이것은 Java 또는 C ++의 작동 방식과 다르다는 점에 유의해야합니다. privateRuby protected에서 하위 클래스가 메소드에 액세스 할 수 있다는 점에서 Java / C ++에서 와 유사합니다 . Ruby에서는 privateJava에서 와 같이 하위 클래스의 메소드에 대한 액세스를 제한 할 방법이 없습니다 .

루비에서의 가시성은 다음과 같은 방법으로 항상 메소드에 액세스 할 수 있기 때문에 대체로 "추천"입니다 send.

irb(main):001:0> class A
irb(main):002:1>   private
irb(main):003:1>   def not_so_private_method
irb(main):004:2>     puts "Hello World"
irb(main):005:2>   end
irb(main):006:1> end
=> nil

irb(main):007:0> foo = A.new
=> #<A:0x31688f>

irb(main):009:0> foo.send :not_so_private_method
Hello World
=> nil

9
아, 알 겠어요. 내 오해는 생각에서 온 privateprotected서브 클래스가 메소드를 상속 할 수 있는지 여부해야했다, 그러나이 방법은 호출 할 수있는 위치에 대해 사실입니다. 감사!
Kyle Slattery

3
또한 보호 된 방법이 아닌 문서를 생성 할 때 RDoc에서는 개인용 메서드를 기본적으로 무시합니다. 항상 --all 플래그를 사용하여 포함시킬 수 있습니다.
jasoares

그러나 당신이 정말로 그것을 원한다면, 재정의 할 수 send없습니까?
Cyoce

78

차이점

  • 누구나 공개 메소드를 호출 할 수 있습니다.
  • 보호 된 메소드를 호출 하거나 클래스의 다른 구성원 (또는 하위 클래스)이 외부에서 보호 된 메소드를 호출 할 수 있습니다. 다른 사람은 할 수 없습니다.
  • 암시 적 수신자의로만 호출 할 수 있으므로 개인 메소드 만 호출 할 수 있습니다 self. 심지어 당신 은 전화를 걸 수 없습니다 self.some_private_method. 당신은 호출해야합니다 private_method으로 self암시.
    • iGEL은 다음과 같이 지적합니다. "하지만 한 가지 예외가 있습니다. age = 전용 메소드가 있다면, 로컬 변수와 분리하기 위해 자체적으로 호출 할 수 있습니다."
    • 때문에 루비 2.7self 수신기가 명시 될 수 self.some_private_method허용됩니다. 런타임 값이와 동일하더라도 다른 명시 적 수신자는 여전히 허용되지 않습니다 self.

루비에서 이러한 차이는 단지 한 프로그래머에서 다른 프로그래머에게 조언입니다. 비공개 방법은 "이것을 변경할 권리가 있으며, 의존하지 마십시오"라고 말하는 방법입니다. 그러나 여전히 날카로운 가위를 얻고 send원하는 방법을 호출 할 수 있습니다.

간단한 튜토리얼

# dwarf.rb
class Dwarf
  include Comparable

  def initialize(name, age, beard_strength)
    @name           = name
    @age            = age
    @beard_strength = beard_strength
  end

  attr_reader :name, :age, :beard_strength
  public    :name
  private   :age
  protected :beard_strength

  # Comparable module will use this comparison method for >, <, ==, etc.
  def <=>(other_dwarf)
    # One dwarf is allowed to call this method on another
    beard_strength <=> other_dwarf.beard_strength
  end

  def greet
    "Lo, I am #{name}, and have mined these #{age} years.\
       My beard is #{beard_strength} strong!"
  end

  def blurt
    # Not allowed to do this: private methods can't have an explicit receiver
    "My age is #{self.age}!"
  end
end

require 'irb'; IRB.start

그런 다음 실행 ruby dwarf.rb하고이 작업을 수행 할 수 있습니다 .

gloin = Dwarf.new('Gloin', 253, 7)
gimli = Dwarf.new('Gimli', 62,  9)

gloin > gimli         # false
gimli > gloin         # true

gimli.name            # 'Gimli'
gimli.age             # NoMethodError: private method `age'
                         called for #<Dwarf:0x007ff552140128>

gimli.beard_strength # NoMethodError: protected method `beard_strength'
                        called for #<Dwarf:0x007ff552140128>

gimli.greet          # "Lo, I am Gimli, and have mined these 62 years.\
                           My beard is 9 strong!"

gimli.blurt          # private method `age' called for #<Dwarf:0x007ff552140128>

8
좋은 설명입니다! 그러나 한 가지 예외가 있습니다. 개인 메소드가있는 경우 로컬 변수 age=self분리하기 위해 호출 할 수 있습니다 .
iGEL

"인사"를 보호 된 방법으로 만든 경우 gimli.greet를 수행 할 수없는 이유는 무엇입니까? gimli는 Dwarf 클래스의 멤버이므로 괴롭힘없이이 메소드를 호출 할 수 없습니까?
JoeyC

@JoeyC 당신이 할 때 때문에 gimli.greet, gimli호출자하지만, 수신기가 아닙니다. 호출자는 "최상위 실행 환경"이며 실제로는의 임시 인스턴스입니다 Object. ruby -e 'p self; p self.class'
Kelvin

52

루비의 프라이빗 메소드 :

메소드가 Ruby에서 개인용 인 경우 명시 적 수신자 (오브젝트)가 메소드를 호출 할 수 없습니다. 암시 적으로 만 호출 할 수 있습니다. 이 클래스는 서브 클래스뿐만 아니라 해당 클래스가 설명 된 클래스에 의해 내재적으로 호출 될 수 있습니다.

다음 예제는 더 잘 설명합니다.

1) 개인 메소드 class_name을 가진 동물 클래스

class Animal
  def intro_animal
    class_name
  end
  private
  def class_name
    "I am a #{self.class}"
  end
end

이 경우 :

n = Animal.new
n.intro_animal #=>I am a Animal
n.class_name #=>error: private method `class_name' called

2) 양서류라는 동물의 서브 클래스 :

class Amphibian < Animal
  def intro_amphibian
    class_name
  end 
end 

이 경우 :

  n= Amphibian.new
  n.intro_amphibian #=>I am a Amphibian
  n.class_name #=>error: private method `class_name' called

보다시피, private 메소드는 암시 적으로 만 호출 할 수 있습니다. 명시적인 수신자가 호출 할 수 없습니다. 같은 이유로, 개인용 메소드는 정의 클래스의 계층 외부에서 호출 될 수 없습니다.

루비에서 보호 된 메소드 :

메소드가 Ruby로 보호되는 경우, 정의 클래스와 해당 서브 클래스 둘 다에 의해 내재적으로 호출 될 수 있습니다. 또한 수신자가 자체 클래스이거나 자체 클래스와 동일한 클래스 인 경우 명시 적 수신자가 호출 할 수도 있습니다.

1) protected 메소드 protect_me를 가진 Animal 클래스

class Animal
  def animal_call
    protect_me
  end
  protected
  def protect_me
    p "protect_me called from #{self.class}"
  end  
end

이 경우 :

n= Animal.new
n.animal_call #=> protect_me called from Animal
n.protect_me #=>error: protected method `protect_me' called

2) 동물 계급에서 물려받은 포유류 계급

class Mammal < Animal
  def mammal_call
    protect_me
  end
end 

이 경우

n= Mammal.new
n.mammal_call #=> protect_me called from Mammal

3) 동물 계급 (포유류 계급과 동일)에서 물려받은 양서류 계급

class Amphibian < Animal
  def amphi_call
    Mammal.new.protect_me #Receiver same as self
    self.protect_me  #Receiver is self
  end   
end

이 경우

n= Amphibian.new
n.amphi_call #=> protect_me called from Mammal
             #=> protect_me called from Amphibian  

4) Tree라는 클래스

class Tree
  def tree_call
    Mammal.new.protect_me #Receiver is not same as self
  end
end

이 경우 :

n= Tree.new
n.tree_call #=>error: protected method `protect_me' called for #<Mammal:0x13410c0>

7

Java의 개인 메소드를 고려하십시오. 물론 같은 클래스 내에서 호출 할 수도 있지만 같은 클래스의 다른 인스턴스에서 호출 할 수도 있습니다.

public class Foo {

   private void myPrivateMethod() {
     //stuff
   }

   private void anotherMethod() {
       myPrivateMethod(); //calls on self, no explicit receiver
       Foo foo = new Foo();
       foo.myPrivateMethod(); //this works
   }
}

따라서 호출자가 동일한 클래스의 다른 인스턴스 인 경우 실제로는 "외부"에서 개인용 메소드에 액세스 할 수 있습니다. 이것은 실제로 그것이 사적인 것이 아닌 것처럼 보입니다.

반면에 루비에서는 프라이빗 메소드가 실제로는 현재 인스턴스에만 프라이빗으로 사용됩니다. 이것이 명시적인 수신자 옵션을 제거하는 것입니다.

다른 한편으로, 루비가 어쨌든 그들을 둘러 볼 수있는 방법을 제공한다는 점에서 루비 커뮤니티에서는 이러한 가시성 컨트롤을 전혀 사용하지 않는 것이 일반적이라는 것을 분명히 지적해야합니다. 자바 세계와는 달리, 모든 것을 접근 가능하게 만들고 다른 개발자가 일을 망치지 않도록 믿습니다.


9
"루비 커뮤니티에서는 이러한 가시성 컨트롤을 전혀 사용하지 않는 것이 일반적입니다"– 이것은 사실 일 수 있지만, 우리는이를 사용해야한다고 말합니다. 상수처럼, 그들은 수갑이 아니라 한 프로그래머에서 다른 프로그래머로의 의사 소통입니다. "나는 이것을 내버려 두는 것이 좋습니다." 내 공개 방법에 의존 할 수 있습니다. 구현 방법을 고려하기 때문에 개인 메서드를 경고없이 변경할 수 있습니다.
Nathan Long

" 루비는, 다른 한편으로는, 개인 방법은 정말 현재 인스턴스 만에 개인하기위한 것입니다. ”이것은 사실이 아니다. 실수로 부모 클래스의 개인 메소드를 덮어 쓸 수 있습니다 (일부 클래스는 API의 일부로 나열 할 수도 있습니다).
Franklin Yu

1
@FranklinYu 그가 쓴 것에 아무런 관련이 없다. Ruby의 프라이버시는 클래스가 아닌 객체 에 관한 것이며 , 메소드를 정의 하지 않고 호출 하는 것에 관한 것입니다. 개인용 메소드는 동일한 오브젝트의 다른 메소드에 의해서만 호출 될 수 있습니다. 방법이 정의 된 클래스와는 아무런 관련이 없습니다.
철학

2

루비에서 서브 클래스로 프라이빗 메소드에 액세스 할 수있는 이유 중 하나는 클래스를 사용한 루비 상속이 모듈 포함에 비해 설탕이 얇기 때문입니다.

http://ruby-doc.org/core-2.0.0/Class.html

이것이 의미하는 바는 기본적으로 서브 클래스가 부모 클래스를 "포함" 하여 프라이빗 함수를 포함한 부모 클래스의 함수 가 서브 클래스에도 효과적으로 정의된다는 것입니다.

다른 프로그래밍 언어에서 메서드를 호출하면 메서드 이름을 부모 클래스 계층으로 버블 링하고 메서드에 응답하는 첫 번째 부모 클래스를 찾습니다. 반대로 Ruby에서는 부모 클래스 계층 구조가 여전히 존재하지만 부모 클래스의 메서드는 하위 클래스의 메서드 목록에 직접 포함됩니다.


2

Ruby와 Java의 액세스 제어 비교 : 메소드가 Java에서 개인용으로 선언 된 경우 동일한 클래스 내의 다른 메소드 만 액세스 할 수 있습니다. 보호 된 것으로 선언 된 메소드는 동일한 패키지 내에 존재하는 다른 클래스 및 다른 패키지에있는 클래스의 서브 클래스에 의해 액세스 될 수 있습니다. 방법이 공개되면 모든 사람이 볼 수 있습니다. Java에서 액세스 제어 가시성 개념은 상속 / 패키지 계층 구조에서 이러한 클래스의 위치에 따라 다릅니다.

Ruby에서는 상속 계층 구조 또는 패키지 / 모듈이 적합하지 않습니다. 그것은 어떤 객체가 메소드의 수신자인지에 관한 것입니다.

Ruby의 개인 메소드의 경우 명시 적 수신자로 호출 할 수 없습니다. 암시 적 수신자를 사용하여 전용 메소드를 호출 할 수 있습니다.

이것은 또한 선언 된 클래스와이 클래스의 모든 서브 클래스에서 전용 메소드를 호출 할 수 있음을 의미합니다.

class Test1
  def main_method
    method_private
  end

  private
  def method_private
    puts "Inside methodPrivate for #{self.class}"
  end
end

class Test2 < Test1
  def main_method
    method_private
  end
end

Test1.new.main_method
Test2.new.main_method

Inside methodPrivate for Test1
Inside methodPrivate for Test2

class Test3 < Test1
  def main_method
    self.method_private #We were trying to call a private method with an explicit receiver and if called in the same class with self would fail.
  end
end

Test1.new.main_method
This will throw NoMethodError

정의 된 클래스 계층 외부에서는 private 메소드를 호출 할 수 없습니다.

private과 같이 암시 적 수신자를 사용하여 보호 된 메소드를 호출 할 수 있습니다. 또한 수신자가 "self"또는 "같은 클래스의 객체"인 경우 명시 적 수신자 (보호 된 메소드)에 의해 protected 메소드를 호출 할 수도 있습니다.

 class Test1
  def main_method
    method_protected
  end

  protected
  def method_protected
    puts "InSide method_protected for #{self.class}"
  end
end

class Test2 < Test1
  def main_method
    method_protected # called by implicit receiver
  end
end

class Test3 < Test1
  def main_method
    self.method_protected # called by explicit receiver "an object of the same class"
  end
end


InSide method_protected for Test1
InSide method_protected for Test2
InSide method_protected for Test3


class Test4 < Test1
  def main_method
    Test2.new.method_protected # "Test2.new is the same type of object as self"
  end
end

Test4.new.main_method

class Test5
  def main_method
    Test2.new.method_protected
  end
end

Test5.new.main_method
This would fail as object Test5 is not subclass of Test1
Consider Public methods with maximum visibility

요약

공개 : 공개 메소드는 최대 가시성을 갖습니다.

Protected : private과 같이 암시 적 수신자를 사용하여 protected 메서드를 호출 할 수 있습니다. 또한 수신자가 "self"또는 "같은 클래스의 객체"인 경우 명시 적 수신자 (보호 된 메소드)에 의해 protected 메소드를 호출 할 수도 있습니다.

개인 : Ruby의 개인 메소드의 경우 명시 적 수신자로 호출 할 수 없습니다. 암시 적 수신자를 사용하여 전용 메소드를 호출 할 수 있습니다. 이것은 또한 선언 된 클래스와이 클래스의 모든 서브 클래스에서 전용 메소드를 호출 할 수 있음을 의미합니다.


0
First Three types of access specifiers and those define thier scope.
1.Public    ->  Access anywhere out side the class.
2.Private   ->  Can not access outside the class. 
3.Protected ->  This Method not access anywhere this method define 
                scope.

But i have a solution for this problem for all method how to access explain in depth. 

class Test
attr_reader :name
def initialize(name)
  @name = name
end

def add_two(number)
  @number = number 
end

def view_address
  address("Anyaddress")
end

private 
def address(add)
   @add = add
end

protected 
def user_name(name)
  # p 'call method'
  @name = name
end
end

class Result < Test
def new_user
  user_name("test355")
end
end
  1. 객체 목록
  2. p 테스트 = Test.new ( "test")
  3. p test.name
  4. p test.add_two (3)
  5. 목록 항목
  6. p test.view_address
  7. pr = Result.new ( "")
  8. 새 사용자

코드 편집에 문제가 있습니다. 두 번째 수업은 한 줄 이전 게시물에 표시됩니다. 이제 모든 메소드에 액세스하는 방법을 설명합니다. 먼저 테스트 클래스 객체를 만듭니다. 비공개 메소드는 클래스 외부에 액세스 할 수 없으며 개인 메소드에 액세스 할 수 있습니다. 메인 객체를 통해 view_address 메소드 액세스를 만듭니다. 또한 보호 된 메소드 액세스는 상속을 작성합니다.
hardik
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.