Classes e Objetos
Tudo em ruby é um objeto. Então vamos aprender a criar os nossos próprios. Para isso, vamos começar criando uma classe chamada Pessoa
.
class Pessoa
def initialize(nome, idade)
@nome = nome
@idade = idade
end
end
pessoa = Pessoa.new("Mc Poze do Rodo", 23)
p pessoa
puts pessoa
Executando o código acima, você vai ver que a classe Pessoa
foi criada como um objeto.
=> #<Pessoa:0x00007fcab271e1c8 @nome="Mc Poze do Rodo", @idade=23>
=> #<Pessoa:0x00007fcab271e1c8>
Como visto acima, Para criarmos uma classe, usamos a palavra-chave class
, seguida pelo nome da classe.
Segundo as convenções de Ruby, nos nomes das classes é utilizado camel case, da mesma maneira que em Java, com maiúsculas separando duas ou mais palavras no nome da classe. Temos então classes com nomes como CachorroCaramelo
, CarroPersonalizado
, MeuComputador
.
As propriedades do nosso objeto são armazenadas no que já explicamos antes e chamamos de variáveis de instância, que são variáveis dentro do objeto cujo nome se inicia com @
. Se fizermos referência para alguma que ainda não foi criada, ela será.
Podemos inicializar várias dessas variáveis dentro do método initialize
, que é o construtor do nosso objeto, chamado após o método new
, que aloca espaço na memória para o objeto sendo criado.
Transformando em string
Podemos ver acima que usando puts
para verificar o nosso objeto, foi mostrada somente a referência dele na memória. Mas, para vermos o objeto completo, precisamos transformar o objeto em string.
Vamos fazer um método novo na classe para mostrar as informações de uma maneira mais bonita. Se lembra que em tipos de dados utilizamos um método chamado to_s
, que converte o objeto em uma String
? Vamos usar ele.
Vamos criar um método para a nossa classe:
class Pessoa
def initialize(nome, idade)
@nome = nome
@idade = idade
end
def to_s
"Nome: #{@nome} Idade: #{@idade}"
end
end
pessoa = Pessoa.new("Mc Poze do Rodo", 23)
p pessoa
puts pessoa
Executando o código acima, você vai ver que a classe Pessoa
foi criada como um objeto, e como o método to_s
foi criado, ele foi chamado automaticamente.
=> #<Pessoa:0x00007f533fb23178 @nome="Mc Poze do Rodo", @idade=23>
=> Nome: Mc Poze do Rodo Idade: 23
attr_reader
Anteriormente vimos como criar nossos objetos e suas propriedades usando variáveis de instância, mas nos podemos lê-las?
Vamos acessá-las usando as nossas variáveis de instância:
class Pessoa
def initialize(nome, idade)
@nome = nome
@idade = idade
end
def to_s
"Nome: #{@nome} Idade: #{@idade}"
end
end
pessoa = Pessoa.new("Mc Poze do Rodo", 23)
puts pessoa.nome
puts pessoa.idade
Ops..
Executando o código acima, você vai ver que a recebemos um erro.
=> undefined method 'nome' for #<Pessoa:0x00007f533fa44888 @nome="Mc Poze do Rodo", @idade=23> (NoMethodError)
=> undefined method 'idade' for #<Pessoa:0x00007f533fa44888 @nome="Mc Poze do Rodo", @idade=23> (NoMethodError)
Essas variáveis são privadas do objeto, e não podem ser lidas sem um método de acesso. Então nos podemos resolver isso usando attr_reader
:
class Pessoa
attr_reader :nome, :idade
def initialize(nome, idade)
@nome = nome
@idade = idade
end
def to_s
"Nome: #{@nome} Idade: #{@idade}"
end
end
pessoa = Pessoa.new("Mc Poze do Rodo", 23)
puts pessoa.nome
puts pessoa.idade
Executando o código agora nos vamos ter a resposta esperada:
=> Mc Poze do Rodo
=> 23
attr_writer
E se agora nos quisermos trocar o nome ou a idade usando as variáveis?
class Pessoa
attr_reader :nome, :idade
def initialize(nome, idade)
@nome = nome
@idade = idade
end
def to_s
"Nome: #{@nome} Idade: #{@idade}"
end
end
pessoa = Pessoa.new("Mc Poze do Rodo", 23)
pessoa.idade = 24
Executando o código acima, você vai ver que recebemos um erro de undefined method
:
=> undefined method `idade=' for #<Pessoa:0x00007f548af5c7c0 @nome="Mc Poze do Rodo", @idade=23> (NoMethodError)
No exemplo do attr_reader
criamos atributos de leitura, que nos permitem a leitura da propriedade. Se precisarmos de algum atributo de escrita, para trocarmos a idade
ou nome
da Pessoa
, podemos usar:
class Pessoa
attr_reader :nome, :idade
attr_writer :idade
def initialize(nome, idade)
@nome = nome
@idade = idade
end
def to_s
"Nome: #{@nome} Idade: #{@idade}"
end
end
pessoa = Pessoa.new("Mc Poze do Rodo", 23)
pessoa.idade = 24
puts pessoa
Executando o código agora nos vamos ter a resposta esperada:
=> Nome: Mc Poze do Rodo Idade: 24
attr_accessor
attr_accessor
é um método que nos ajuda a fazer o que foi ensinado acima de uma forma mais fácil e menos repetitiva. Como por exemplo:
class Pessoa
attr_accessor :nome, :idade
def initialize(nome, idade)
@nome = nome
@idade = idade
end
def to_s
"Nome: #{@nome} Idade: #{@idade}"
end
end
pessoa = Pessoa.new("Mc Poze do Rodo", 23)
pessoa.idade = 21
pessoa.nome = "MC Poze Pitbull do Funk"
puts pessoa
Executando o código agora nos vamos ter a resposta esperada:
=> Nome: MC Poze Pitbull do Funk Idade: 21
Variáveis de Classe
Também podemos criar variáveis de classe, que são variáveis que são compartilhadas por todos os objetos da classe.
class Pessoa
attr_accessor :nome, :idade
@@contador = 0
def initialize(nome, idade)
@nome = nome
@idade = idade
@@contador += 1
end
def to_s
"Nome: #{@nome} Idade: #{@idade}"
end
def self.contador # utilizando self para não precisar de um objeto para acessar a variável de classe. Sem o self iriamos precisar usar o objeto Poze.contador para acessar a variável de classe.
@@contador
end
end
pessoa = Pessoa.new("Mc Poze do Rodo", 23)
puts Pessoa.contador
Executando o código nos vamos ter a resposta esperada:
=> 1
Herança
Em Ruby, temos herança única, que significa que uma classe pode apenas ser criada herdando de apenas outra classe, reduzindo a complexidade do código. Dessa forma, podemos ao invés de repetir a definição de métodos por classes similares, pode realizar essa operação em uma única classe (também chamada de superclasse) e as outras que possuem métodos comuns (chamadas de subclasses) herdam essas funcionalidades da sua superclasse. A herança ajuda a reduzir substancialmente a duplicação de código. Como por exemplo:
class Pessoa
attr_accessor :nome, :idade
@@contador = 0
def initialize(nome, idade)
@nome = nome
@idade = idade
@@contador += 1
end
def to_s
"Nome: #{@nome} Idade: #{@idade}"
end
def self.contador
@@contador
end
end
class OutraPessoa < Pessoa
def to_s
"Outra pessoa: #{super}"
end
end
pessoa = Pessoa.new("Mc Poze do Rodo", 23)
pessoa2 = OutraPessoa.new("Beethoven", 56)
puts pessoa
puts pessoa2
Executando o código nos vamos ter a resposta esperada:
=> Nome: Mc Poze do Rodo Idade: 23
=> Outra pessoa: Nome: Beethoven Idade: 56
Espero que tenha entendido como funcionam classes e objetos em ruby. Isso não é tudo desse tema, mas é o suficiente para que você possa começar a aprender a programar usando classes e objetos. 😉