RSS Feed

Classes e Módulos – Visibilidade: Public, Protected e Private.

30/11/2011 by Uriel Juliatti Valle

Métodos de instância podem ser public, private ou protected. Se você veio de outras linguagens de programação orientadas a objeto, provavelmente já está familiarizado com esses termos e com o forte e importante conceito de encapsulação. Mesmo com esse background, não subestime, pois no Ruby alguns desses termos podem ter um significado um pouco diferente.

Public

Geralmente  - e por padrão –  os métodos em ruby são públicos, ao menos que você especifique a visibilidade. Além disso, podem ser chamados de qualquer lugar, pois não há restrição quanto ao seu uso. Mas há uma exceção em cena – o initialize – que é por natureza private. Outras exceções, tais como qualquer método declarado fora da definição da classe – e que podem ser considerados “globais” - também são definidos como private e são métodos específicos de Object.

Private

Um método privado é específico para uma implementação de uma classe e só pode ser chamado por outros métodos de instância de uma classe ou subclasses. Entretanto, métodos privados são implicitamente chamados com self e não podem ser explicitamente chamados em um objeto. Por exemplo, se um método m é private você só pode chamá-lo de forma funcional, como m. É impossível chamar como o.m ou self.m.

Protected

Um método protected é como um método private que só pode ser chamado dentro da implementação da classe ou suas subclasses. A diferença de um método private é que ele pode ser chamado em qualquer instância da classe e não é restrito à chamada implícita do self. Um método protected pode ser usado, por exemplo, em uma situação em que você define um acessor que permita compartilhar os estados dos objetos uns com os outros, mas não permite que os usuários daquela classe tenham acesso aos estados.

Além disso…

Private, protected e public são métodos de instância da classe Module. Em ruby, todas as classes são módulos e dentro da definição da classe, mas fora da definição dos métodos, self refere-se sempre à classe que está sendo definida em questão.

Boas práticas:

Ao declarar métodos private e protected procure alinhá-los ao final da classe

1
2
3
4
5
6
7
8
9
10
11
12
class Test
 
def initialize(x, y)
@x, @y = x, y
end
 
private
def backgroud_proc
nil
end
 
end
class Test

def initialize(x, y)
@x, @y = x, y
end

private
def backgroud_proc
nil
end

end

Uma outra é que você pode declarar a visibilidade do método sempre após a sua definição, assim:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Foo
 
def x
@x
end
protected : x
 
def utility_method
nil
end
private :utility_method
 
end
class Foo

def x
@x
end
protected : x

def utility_method
nil
end
private :utility_method

end

 

Um outro detalhe importante, mas muito importante  é que a visibilidade public, private e protected aplicam-se apenas aos métodos em Ruby. Variáveis de classe e instância são sempre encapsuladas e definidas como private por padrão, as constantes são sempre públicas – violar essas regras podem custar erros no interpretador. Por fim, não tente definir uma variável como public e acessá-la diretamente, pois como dito, não terá êxito.Uma das formas de fazer esse “acesso direto” é por intermédio dos accessors (attrs) que o ruby oferece – e que facilita muito a nossa vida como desenvolvedor.

Alguns casos são interessantes para se analisar, por exemplo, caso você venha a executar uma fabricação de um objeto (Factory Method) em sua classe, pode vir a necessidade de tornar o método de classe new privado. Para tornar isso possível, utilize o método private_class_method especificando um ou mais nome de métodos – new no nosso caso – como símbolo.

1
private_class_method :new
private_class_method :new

Da mesma forma que você o torna private, você pode torná-lo público com o método public_class_method :new.

Obs: Nenhum método pode ser chamado sem argumentos da mesma forma que o public, protected e private são.

Levando em consideração a flexibilidade da linguagem ruby, suas robustez – que pouco conheço – é importante conhecer  e entender, no entanto, que as capacidades de metaprogramação do Ruby também torna confortável chamar métodos privados e protegidos e até mesmo acessar variáveis ​​de instância encapsuladas.

Dessa forma, se quiséssemos acessar o método privado utility_method declarado anteriormente, poderíamos utilizar o método send, ou até mesmo o método instance_eval para avaliar um bloco no contexto do objeto corrente:

1
2
3
4
5
6
7
8
ruby-1.9.2-p290 :032 > f = Foo.new
=> #<Foo:0x007fba4969d1a0>
ruby-1.9.2-p290 :033 > f.send :utility_method # chamando um método privado!
=> nil
ruby-1.9.2-p290 :034 > f.instance_eval { utility_method } # chamando novamente um método privado!
=> nil
ruby-1.9.2-p290 :035 > f.instance_eval { @x } # lendo uma variável de instância de f
=> nil
ruby-1.9.2-p290 :032 > f = Foo.new
=> #<Foo:0x007fba4969d1a0>
ruby-1.9.2-p290 :033 > f.send :utility_method # chamando um método privado!
=> nil
ruby-1.9.2-p290 :034 > f.instance_eval { utility_method } # chamando novamente um método privado!
=> nil
ruby-1.9.2-p290 :035 > f.instance_eval { @x } # lendo uma variável de instância de f
=> nil

Lindo, não?!

Ainda farei uma cobertura mais abrangente sobre o send e instance_eval quando abordarmos a metaprogramação de uma forma mais investigativa :)

Então é isso, fechamos mais um episódio com métodos de acesso e acessibilidade no Ruby, o próximo passo será investigar sobre Herança e Subclasses.

Até a próxima!


1 Comment »

  1. Mario Vargas says:

    Muito bom cara! Tenho acompanhado seu blog e vi vc progredindo mto! Abs!!

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code lang=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" extra="">