145 votes

Pourquoi Ruby a-t-il des méthodes privées et protégées?

Avant que j'ai lu cet article, j'ai pensé que le contrôle d'accès dans Ruby a travaillé comme ceci:

  • public - peut être consulté par n'importe quel objet (par exemple, Obj.new.public_method)
  • protected - ne peut être consulté à partir de l'objet lui-même, ainsi que toutes les sous-classes
  • private - mêmes protégées, mais la méthode n'existe pas dans les sous-classes

Cependant, il semble que l' protected et private agir de la même, sauf pour le fait que vous ne pouvez pas appeler private méthodes explicitement avec un récepteur (c'est à dire self.protected_method fonctionne, mais self.private_method n'en ont pas).

Quel est le point de tout cela? Quand il y a un scénario si vous ne voulez pas que votre méthode appelée explicitement avec un récepteur?

171voto

dbyrne Points 18604

protected méthodes peuvent être appelées par une instance de la classe de définition ou de ses sous-classes.

private méthodes peuvent être appelées qu'à partir de l'objet appelant. Vous ne pouvez pas accéder à une autre instance privée de méthodes directement.

Voici un petit exemple pratique:

def compareTo(x)
 self.someMethod <=> x.someMethod
end

someMethod ne peut pas être private ici. Il doit être protected parce que vous avez besoin de soutien explicite des récepteurs. Votre intérieur typique des méthodes d'assistance peuvent généralement être private depuis ils n'ont jamais besoin d'être appelé comme ça.

Il est important de noter que ceci est différent de la façon dont Java ou C++ fonctionne. private en Ruby, c'est similaire à l' protected en Java/C++ dans les sous-classes ont accès à cette méthode. En Ruby, il n'existe aucun moyen de restreindre l'accès à une méthode à partir de ses sous-classes comme vous le pouvez avec private en Java.

La visibilité en Ruby, c'est en grande partie une "recommandation" de toute façon puisque vous pouvez toujours accéder à une méthode utilisant l' 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

80voto

Nathan Long Points 30303

La différence

  • N'importe qui peut appeler vos méthodes publiques.
  • Vous pouvez appeler votre protégé méthodes, ou un autre membre de votre classe (ou d'un descendant de la classe) pouvez appeler votre protégé méthodes de l'extérieur. Personne d'autre ne peut.
  • Seulement vous pouvez appeler vos méthodes privées, parce qu'elles ne peuvent être appelées avec un récepteur implicite de l' self. Même vous, vous ne peut pas appeler self.some_private_method; vous devez appeler private_method avec self implicite. (iGEL souligne: "Il n'y a toutefois une exception. Si vous avez une méthode privée âge=, vous pouvez (et devez) appeler avec des auto de le séparer de variables locales.")

En Ruby, ces distinctions sont juste des conseils d'un programmeur à l'autre. Non méthodes publiques sont une façon de dire "je me réserve le droit de modifier la présente; ne dépend pas d'elle." Mais vous obtenez toujours les ciseaux pointus d' send et peut appeler n'importe quelle méthode que vous aimez.

Un bref tutoriel

# 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

Ensuite, vous pouvez exécuter ruby dwarf.rb et faire:

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>

7voto

Jacob Mattison Points 32137

Envisager une méthode privée en Java. Elle peut être appelée à partir de l'intérieur de la même classe, bien sûr, mais elle peut également être appelée par une autre instance de la même classe:

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

Donc, si l'appelant est un autre exemple de ma classe, ma méthode est en fait accessible à partir de l ' "extérieur", pour ainsi dire. De ce fait, il est semble pas que privé.

En Ruby, d'autre part, une méthode privée est vraiment censé être privé, uniquement à l'instance en cours. C'est ce que la suppression de l'option explicite le récepteur fournit.

D'autre part, je voudrais souligner que c'est assez commune dans la communauté Ruby de ne pas utiliser ces contrôles de visibilité à tous, étant donné que Ruby vous donne les moyens de les contourner, de toute façon. À la différence dans le monde Java, la tendance est de tout rendre accessible et de faire confiance à d'autres développeurs de ne pas visser les choses.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X