programing

왜 Ruby는 개인적인 방법과 보호된 방법을 모두 가지고 있습니까?

firstcheck 2023. 6. 2. 22:40
반응형

왜 Ruby는 개인적인 방법과 보호된 방법을 모두 가지고 있습니까?

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

  • public 모든개예체예(:)로 수 .Obj.new.public_method)
  • protected는 객체 자체 수 , 하위 는 물론 하위 클래스에서 수 있습니다.
  • private하위 .

하지만, 다음과 같이 보입니다.protected그리고.private전화를 할 수 없다는 사실을 제외하고는 똑같이 행동합니다.private 명적수시있즉방는법가기신즉▁with방(법,▁an,self.protected_method 작하지만동,▁works동작만.self.private_method하지 않음).

이게 무슨 의미가 있습니까?명시적 수신기를 사용하여 메서드를 호출하지 않으려는 시나리오는 언제입니까?

protected메서드는 정의 클래스 또는 해당 하위 클래스의 인스턴스에 의해 호출될 수 있습니다.

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

다음은 간단한 실용적인 예입니다.

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

some_method가 될 수 .private 요기일 예요. 틀림없이protected명시적 수신기를 지원하기 위해 필요하기 때문입니다.일반적인 내부 도우미 방법은 다음과 같습니다.private그들은 결코 이렇게 불릴 필요가 없기 때문입니다.

이것은 Java 또는 C++의 작동 방식과는 다릅니다. private는 루비경유사다니합우와의와 합니다.protected하위 클래스에서 메서드에 액세스할 수 있는 Java/C++입니다.루비처럼 클래스에서 를 제한할 수 .private자바로

은 Ruby를 에 항상 액세스할 있기 에 대부분 "권장"입니다.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

차이

  • 누구나 공용 메소드를 호출할 수 있습니다.
  • 보호된 메서드를 호출하거나 클래스의 다른 구성원(또는 하위 클래스)이 외부에서 보호된 메서드를 호출할 수 있습니다.아무도 할 수 없습니다.
  • 메서드만 호출할 수 . 메서드는 할 수 입니다.self당신도 전화를 할 수 없습니다.self.some_private_method꼭전보요세에 전화해야 .private_method와 함께self묵시의
    • iGEL은 다음과 같이 지적합니다. "하지만 한 가지가 있습니다.개인 메소드 연령=이 있는 경우 로컬 변수와 구분하기 위해 스스로 호출할 수 있습니다."
    • Ruby 2.7 이후로self일 수 .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>

Ruby의 개인 메서드:

메서드가 Ruby에서 비공개인 경우 명시적 수신기(개체)에서 호출할 수 없습니다.암시적으로만 호출할 수 있습니다.이 클래스는 에서 설명한 클래스와 이 클래스의 하위 클래스에 의해 암시적으로 호출될 수 있습니다.

다음 예를 통해 더 잘 알 수 있습니다.

개인 메서드 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

양서류라고 불리는 동물의 하위 분류:

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

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

Ruby의 보호된 메서드:

메서드가 Ruby에서 보호되는 경우 정의 클래스와 하위 클래스 모두에서 메서드를 암시적으로 호출할 수 있습니다.또한 수신기가 자기 또는 자기와 동일한 클래스인 한 명시적 수신기에 의해 호출될 수 있습니다.

보호 메서드 protect_me가 있는 동물 클래스

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

동물 등급에서 상속된 포유류 등급

class Mammal < Animal
  def mammal_call
    protect_me
  end
end 

이 경우

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

동물 분류에서 물려받은 양서류 분류(포유류 분류와 동일)

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  

트리라는 클래스

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>

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
   }
}

그래서 -- 만약 발신자가 제 클래스의 다른 인스턴스라면 -- 말하자면, 제 개인적인 방법은 "외부"에서 접근할 수 있습니다.이것은 사실 그것을 그렇게 사적인 것으로 보이지 않게 만듭니다.

반면에 Ruby에서 Private 메서드는 현재 인스턴스에만 Private로 지정됩니다.이것이 명시적 수신기의 옵션을 제거하는 것입니다.

다른 한편으로, 저는 루비 커뮤니티에서 이러한 가시성 컨트롤을 전혀 사용하지 않는 것이 꽤 흔하다는 것을 분명히 지적해야 합니다. 루비는 어쨌든 이러한 컨트롤을 피할 수 있는 방법을 제공하기 때문입니다.자바 세계와는 달리, 모든 것을 접근 가능하게 하고 다른 개발자들이 일을 망치지 않도록 신뢰하는 경향이 있습니다.

뭐가 달라요?

개인 방법 설명

@freddie = Person.new
@freddie.hows_it_going?
# => "oh dear, i'm in great pain!"

class Person   
    # public method
    def hows_it_going?
        how_are_your_underpants_feeling?
    end

    private

    def how_are_your_underpants_feeling? # private method
        puts "oh dear, i'm in great pain!"
    end
end

우리는 프레디에게 공개적인 방법으로 상황이 어떻게 진행되고 있는지 물어볼 수 있습니다.그것은 완벽하게 타당합니다.그리고 그것은 정상적이고 받아들여집니다.

하지만... 프레디의 팬티 상황을 알 수 있는 유일한 사람은 프레디 자신입니다.아무도 모르는 사람들이 프레디의 팬티 속으로 손을 뻗는 것은 좋지 않을 것입니다. 아니요, 그건 매우 사적인 일입니다. 그리고 우리는 사적인 것을 외부에 노출시키고 싶지 않습니다.다시 말해서, 우리는 세계의 어떤 발신자에게도 가변적인 데이터를 노출시키고 싶지 않을 수 있습니다.누군가가 값을 변형시킬 수도 있고, 우리는 그 벌레가 어디서 왔는지 알아내려고 애쓰며 고통의 세계에 빠질 것입니다.

@freddie.how_are_your_underpants_feeling?
# => # NoMethodError: private method `how_are_your_underpants_feeling?' called

보호된 방법 설명

고려 사항:

class Person    
    protected

    def hand_over_the_credit_card! # protected method
        puts "Lawd have mercy. Whatever. Here it is: 1234-4567-8910"
    end
end

class Rib < Person
end

class Wife < Rib # wife inherits from Rib
    def i_am_buying_another_handbag_with_your_card(husband)        
        husband.hand_over_the_credit_card! # equalityInAction    
    end
end

@husband = Person.new
@mrs = Wife.new
@mrs.i_am_buying_another_handbag_with_your_card(@husband)
# => puts "Lawd have mercy. Whatever. Here it is: 1234-4567-8910"

우리는 어느 정도 괜찮습니다.mrs우리의 신용카드 세부 정보를 얻는 것, 주어진.mrs사람으로부터 물려받은 우리의 살점입니다. 그래서 그녀는 신발 등에 그것을 불 수 있지만, 우리는 무작위의 개인이 우리의 신용카드 세부 정보에 접근하는 것을 원하지 않습니다.

하위 클래스 밖에서 이 작업을 수행하려고 하면 실패합니다.

@mrs = Wife.new
@mrs.gimme_your_credit_card!
# => protected method hand_over_the_credit_card! called for #<Wife:0x00005567b5865818> (NoMethodError)

요약

  • 개인 메서드는 "명시적 수신기" 없이 내부에서만 호출할 수 있습니다. (엄밀히 말하자면, 루비 마법을 조금 사용하여 개인 메서드에 액세스할 수 있지만, 현재로서는 무시하겠습니다.)
  • 보호된 메서드를 하위 도메인 내에서 호출할 수 있습니다.
  • 저는 여러분이 생생하게 기억할 수 있도록 예시/유용어를 사용했습니다.

Ruby의 하위 클래스에서 개인 메서드에 액세스할 수 있는 이유 중 일부는 클래스가 포함된 Ruby 상속이 모듈을 포함하는 얇은 설탕 코팅이기 때문입니다. 실제로 Ruby에서 클래스는 상속 등을 제공하는 일종의 모듈입니다.

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

이것이 의미하는 바는 기본적으로 하위 클래스가 상위 클래스를 "포함"하여 개인 기능을 포함한 상위 클래스의 기능이 하위 클래스에서도 효과적으로 정의된다는 것입니다.

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

Java의 접근통제와 Ruby의 비교 : Java에서 method가 private로 선언된 경우 동일 클래스 내의 다른 method만 접근할 수 있습니다.메서드가 보호된 것으로 선언되면 동일한 패키지 내에 있는 다른 클래스와 다른 패키지에 있는 클래스의 하위 클래스에서 액세스할 수 있습니다.방법이 공개되면 모든 사람이 볼 수 있습니다.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

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

보호된 메서드는 비공개와 마찬가지로 암시적 수신기를 사용하여 호출할 수 있습니다.또한 보호된 메서드는 수신기가 "자체" 또는 "동일한 클래스의 개체"인 경우에만 명시적 수신기에 의해 호출될 수 있습니다.

 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

요약

Public(공용): Public(공용) 메서드는 가시성이 최대입니다.

보호됨: 보호된 메서드는 비공개와 마찬가지로 암시적 수신기를 사용하여 호출할 수 있습니다.또한 보호된 메서드는 수신기가 "자체" 또는 "동일한 클래스의 개체"인 경우에만 명시적 수신기에 의해 호출될 수 있습니다.

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

처음 세 가지 유형의 액세스 지정자와 그 범위를 정의합니다.

  1. 공용 -> 클래스 외부의 모든 위치에 액세스합니다.
  2. 비공개 -> 클래스 외부에서 액세스할 수 없습니다.
  3. 보호됨 -> 이 메서드는 범위를 정의하는 모든 위치에 액세스할 수 없습니다.

하지만 저는 이 문제에 대한 해결책을 가지고 있습니다. 어떻게 자세히 설명할 수 있는지에 대한 모든 방법에 대해서요.

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 = Test.new("test")
  3. p test.name
  4. p test.add_2(3)
  5. 리스트 항목
  6. ptest.view_address
  7. pr = Result.new("")
  8. pr.new_user

언급URL : https://stackoverflow.com/questions/3534449/why-does-ruby-have-both-private-and-protected-methods

반응형