Ruby: Entendendo Classes, Objetos e Variáveis
Ruby é uma linguagem dinâmica, elegante e poderosa, conhecida por sua sintaxe limpa e expressiva. Um dos aspectos mais importantes de Ruby é seu modelo de programação orientada a objetos, que permite estruturar códigos de forma intuitiva e eficiente. Neste artigo, vamos explorar os fundamentos de classes, objetos e variáveis em Ruby, desvendando a simplicidade e potência desses conceitos.
A Base da Orientação a Objetos em Ruby
Em Ruby, tudo é um objeto. Esta não é apenas uma afirmação retórica - é um princípio fundamental da linguagem. Desde números e strings até as próprias classes, tudo em Ruby é instanciado a partir de uma classe. Esta característica proporciona uma consistência valiosa para quem está aprendendo a linguagem.
Definindo Classes
Vamos começar com um exemplo prático. Imagine que estamos gerenciando uma livraria de livros usados. Precisamos desenvolver um sistema que realize o controle de estoque, processando arquivos CSV que contêm informações como ISBN e preço dos livros.
Uma boa abordagem para design orientado a objetos é identificar os conceitos do domínio. No nosso caso, um conceito fundamental é o livro em estoque. Podemos representá-lo com uma classe:
class BookInStock def initialize(isbn, price) @isbn = isbn @price = Float(price) end end
Esta simples declaração já nos permite criar instâncias:
a_book = BookInStock.new("isbn1", 3) another_book = BookInStock.new("isbn2", 3.14)
O Método Initialize
O método initialize
é especial em Ruby. Quando você chama BookInStock.new
, Ruby aloca memória para um objeto não inicializado e então chama o método initialize
desse objeto, passando todos os argumentos que foram passados para new
.
Isso permite configurar o estado inicial do objeto. No nosso exemplo, o método initialize
transfere os parâmetros para as variáveis de instância @isbn
e @price
. Note o símbolo @
- ele identifica variáveis de instância em Ruby, que são armazenadas com cada objeto e acessíveis em todos os métodos desse objeto.
Objetos e Atributos
As variáveis de instância são encapsuladas nos objetos - são privadas por padrão. Isso é vantajoso, pois garante que o objeto seja responsável por manter sua própria consistência. Porém, precisamos definir métodos que permitam ao mundo exterior interagir com o objeto. Esses aspectos visíveis externamente são chamados de atributos.
Métodos de Acesso
Ruby facilita a criação de métodos acessores através de atalhos convenientes:
class BookInStock attr_reader :isbn, :price # Cria métodos de leitura attr_accessor :price # Cria métodos de leitura e escrita def initialize(isbn, price) @isbn = isbn @price = Float(price) end end
O método attr_reader
cria métodos para leitura, enquanto attr_accessor
cria métodos para leitura e escrita. Isso permite acessar atributos de forma simples e elegante:
book = BookInStock.new("isbn1", 33.80) puts "ISBN = #{book.isbn}" # Lendo um atributo book.price = book.price * 0.75 # Modificando um atributo
Atributos São Apenas Métodos
Um conceito fundamental em Ruby é que atributos são apenas métodos sem argumentos. Eles não necessariamente precisam apenas retornar ou atribuir valores a variáveis de instância. Você pode implementar lógica mais complexa:
def price_in_cents (price * 100).round end def price_in_cents=(cents) @price = cents / 100.0 end
Isso cria uma variável de instância "virtual". Para o mundo exterior, price_in_cents
parece ser um atributo como qualquer outro, mas internamente não possui variável de instância correspondente.
Este princípio, conhecido como "Princípio do Acesso Uniforme", é poderoso - você oculta a implementação do resto do mundo, tendo liberdade para alterá-la no futuro sem impactar o código que utiliza sua classe.
Classes Trabalhando Juntas
Resolver problemas complexos geralmente envolve múltiplas classes trabalhando juntas. No nosso exemplo da livraria, além da classe BookInStock
, podemos criar uma classe CsvReader
para processar os arquivos CSV:
class CsvReader def initialize @books_in_stock = [] end def read_in_csv_data(csv_file_name) CSV.foreach(csv_file_name, headers: true) do |row| @books_in_stock << BookInStock.new(row["ISBN"], row["Price"]) end end def total_value_in_stock sum = 0.0 @books_in_stock.each { |book| sum += book.price } sum end end
Esta abordagem de dividir responsabilidades entre classes torna o código mais modular, legível e manutenível.
Controle de Acesso
Ruby oferece três níveis de controle de acesso para métodos:
- Public: Métodos acessíveis por qualquer código (padrão)
- Protected: Métodos acessíveis apenas por objetos da mesma classe ou subclasses
- Private: Métodos que só podem ser chamados no contexto do objeto atual
Isso permite controlar quanta exposição sua classe terá ao mundo exterior:
class MyClass def method1 # Método público end protected def method2 # Método protegido end private def method3 # Método privado end end
Variáveis e Referências
Em Ruby, variáveis não são objetos - são referências a objetos. Os objetos existem em um "pool" (geralmente a heap do sistema operacional) e são apontados por variáveis. Isso tem implicações importantes:
person1 = "Tim" person2 = person1 # Ambos apontam para o mesmo objeto person1[0] = 'J' # Modifica o objeto puts person2 # Exibe "Jim", não "Tim"
Se quiser evitar esse comportamento, você pode usar dup
para criar uma cópia do objeto, ou freeze
para impedir modificações.
Reabrindo Classes
Uma característica única de Ruby é a capacidade de reabrir uma definição de classe e adicionar novos métodos ou variáveis a qualquer momento, mesmo para classes da biblioteca padrão:
class String def reverso_e_maiusculo reverse.upcase end end puts "teste".reverso_e_maiusculo # Imprime "ETSET"
Essa técnica, conhecida como "monkey patching", pode ser poderosa, mas deve ser usada com cautela para evitar comportamentos imprevisíveis.
Conclusão
O modelo de objetos em Ruby é simples, consistente e flexível, tornando a linguagem uma excelente escolha para programação orientada a objetos. A sintaxe expressiva e os atalhos convenientes permitem escrever código limpo e elegante, enquanto os conceitos sólidos de OO proporcionam uma base robusta para aplicações complexas.
Se você está começando com Ruby ou buscando aprofundar seus conhecimentos em programação orientada a objetos, explorar esses conceitos fundamentais será um passo valioso na sua jornada de aprendizado.
Nenhum comentário:
Postar um comentário