Aprenda Ruby

  • Página Inicial
  • Contato!
  • Tudo sobre Ruby Parte 1!
  • Tudo sobre Ruby Parte 2!
  • Tudo sobre Ruby Parte 3!
  • Tudo sobre Ruby Parte 4!
  • Orientação a Objetos em Ruby - Parte 1

    Criando Classes e Objetos

    Para criar uma classe, basicamente fazemos assim:

    
    class Telefone
    
    end
    
    

    PS: As classes em Ruby nunca são fecchadas, mesmo as padrões, e podem ser adicionadas novos atributos e métodos, mas não é recomendado fazer isso.

    Para criar um objeto dessa classe, basta isso:

    
    tel = Telefone.new # Pode ser com ou sem parênteses
    
    

    Podemos adicionar atributos e métodos na classe, assim:

    
    class Telefone
        attr_writer :numero, :operadora
    
        def dados
            puts "O número é #{@numero} e a operadora é a #{@operadora}."
        end
    end
    
    

    O @ é como o "this" de outras linguagens, ou seja, auto-referência ao objeto criado. O attr_writer permite a gente escrever no atributo.

    PS: O arroba só funciona em atributos. Para métodos use self..

    Dessa forma, podemos fazer as modificações no objeto assim:

    
    tel = Telefone.new
    
    tel.numero = "123-4567"
    tel.operadora = "Vivo"
    
    tel.dados
    
    

    Quando criamos uma classe, temos mais trabalho para fazê-la, mas depois que ela está pronta, podemos criar quantos objetos precisarmos vindos dessa mesma classe, e o programa principal fica mais simples, menor e mais natural. Os objetos criados dessa mesma classe são independentes entre si e o status de um não interfere no outro. Essa é uma das vantagens da orientação a objetos.

    PS: Caso precise declarar um objeto como nulo, use nil. E para pegar o nome da classe, use self.class.

    Encapsulamento e Construtor

    Para marcar atributos como privados, fazemos assim, usando o modificador private:

    
    class Telefone
        attr_writer :numero, :operadora
        private :numero, :operadora
    
        def dados
            puts "O número é #{@numero} e a operadora é a #{@operadora}."
        end
    end
    
    

    Dessa forma, só poderemos mexer nele através de métodos getters e setters. Os métodos getters são definidos colocando nos atributos attr_reader, os setters com attr_writer e ambos com attr_accessor, por exemplo:

    
    class Telefone
        attr_accessor :numero, :operadora
    
        def dados
            puts "O número é #{@numero} e a operadora é a #{@operadora}."
        end   
    end
    
    

    E chamamos normalmente assim:

    
    tel = Telefone.new
    
    tel.numero = "123-4567"
    tel.operadora = "Vivo"
    
    tel.dados
    
    

    Para explicitar o encapsulamento, podemos colocar os atributos e métodos como public (padrão), protected ou private, assim:

    
    class Telefone
        attr_accessor :numero, :operadora
        private :numero, :operadora
    
        public
        def dados
            puts "O número é #{@numero} e a operadora é a #{@operadora}."
        end   
    end
    
    

    Para definirmos um construtor, usamos o método initialize, assim:

    
    class Telefone
        attr_accessor :numero, :operadora
        private :numero, :operadora
    
        public
        def dados
            puts "O número é #{@numero} e a operadora é a #{@operadora}."
        end
    
        def initialize(numero, operadora)
            @numero = numero
            @operadora = operadora
        end
    end
    
    

    E na criação do objeto:

    
    tel = Telefone.new("123-4567", "Vivo")
    
    tel.dados
    
    

    Atributos e Métodos Estáticos

    Os atributos estáticos são definidos com dois arrobas e um getter e setter com o mesmo nome. Os métodos estáticos são os que obrigatoriamente terem self. na frente. Veja um exemplo:

    
    class Numeros
        attr_accessor :num
        @@num = 50
    
        def self.apresentacao
            puts "O número é #{@@num}."
        end
    
        def self.num
            @@num
        end
    
        def self.num=(n)
            @@num = n
        end
    end
    
    

    E para exibir:

    
    Numeros.num = 100
    
    Numeros.apresentacao
    
    

    PS: Métodos estáticos só podem trabalhar outros métodos e atributos quando estes também forem estáticos, e não podem ser sobrepostos. E atributos estáticos é recomendável eles serem inicializados.

    Herança

    Vamos considerar a seguinte classe:

    
    class Veiculo
        attr_accessor :modelo, :potencia
        private :modelo, :potencia
    
        def apresentacao
            puts "O #{self.class.to_s.downcase} é do modelo #{@modelo}, potência #{@potencia}."
        end
    
        def initialize(modelo, potencia)
            @modelo = modelo
            @potencia = potencia
        end
    end
    
    

    Para fazer uma herança, basta colocar o operador < seguido do nome da classe Pai. Caso tenha sobreposição de construtor ou outro método, use o super. Veja um exemplo:

    
    class Carro < Veiculo
        def initialize(modelo, potencia)
            super(modelo, potencia)
        end
    end
    
    

    Instanciação da classe:

    
    fusca = Carro.new("Fusca", 1.6)
    
    fusca.apresentacao
    
    

    A mesma classe Veiculo pode gerar outras classes, como por exemplo Moto e Onibus.

    PS: O Ruby não suporta herança múltipla, mas podemos simular usando um include, dessa forma:

    
    class Carro < Veiculo
        include Transporte
    end
    
    

    Abstração e Polimorfismo

    Podemos simular classes e métodos abstratos, assim:

    
    class Energia
        def ligar
            raise NotImplementedError, "Implemente o método \"ligar\"!"
        end
    
        def desligar
            raise NotImplementedError, "Implemente o método \"desligar\"!"
        end
    end
    
    

    E as classes herdeiras:

    
    class Lampada < Energia
        # Métodos sobrepostos
        def ligar
            puts "A Lâmpada está acesa!"
        end
    
        def desligar
            puts "A Lâmpada apagou!"
        end
    end
    
    

    A outra classe:

    
    class Televisao < Energia
        # Métodos sobrepostos
        def ligar
            puts "A TV está ligada!"
        end
    
        def desligar
            puts "A TV desligou!"
        end
    end
    
    

    A instanciação:

    
    lamp = Lampada.new
    
    lamp.ligar
    lamp.desligar
    
    tv = Televisao.new
    
    tv.ligar
    tv.desligar
    
    

    No entanto, o melhor é simular uma interface com a gem, assim:

    
    require "interface"
    
    Energia = interface {
        required_methods :ligar, :desligar
    }
    
    

    E as classes implementadoras:

    
    class Lampada
        def ligar
            puts "A Lâmpada está acesa!"
        end
    
        def desligar
            puts "A Lâmpada apagou!"
        end
    
        implements Energia
    end
    
    

    A outra classe:

    
    class Televisao
        def ligar
            puts "A TV está ligada!"
        end
    
        def desligar
            puts "A TV desligou!"
        end
    
        implements Energia
    end
    
    

    PS: Qualquer método pode ser sobreposto, caso chame ele na classe filha, use o método super.nomeDoMetodo() para isso. As classes com métodos abstratos e interfaces não podem ser instanciadas.

    Agregação de Objetos

    Vamos supor essa classe:

    
    class Pilha
        attr_accessor :marca, :carga
    
        public
        def initialize(marca)
            @marca = marca
            @carga = 100
        end
    
        public
        def apresentacao
            puts "A marca da pilha é #{@marca}."
            puts "A carga da pilha é #{@carga}%."
        end
    end
    
    

    Nós podemos fazer relacionamentos entre classes diferentes, veja por exemplo a classe abaixo, que tem um atributo do "tipo" da classe acima:

    
    class Aparelho
        attr_accessor :pl
    
        public
        def initialize(pl)
            @pl = pl
        end
    
        public
        def ligado
            if @pl.carga > 0 then # Getter do objeto Pilha
                puts "O aparelho está ligado e a carga da pilha é de #{@pl.carga)}%!"
            else
                puts "A pilha do aparelho está sem carga!"
            end
        end
    end
    
    

    Aí podemos chamar os objetos assim:

    
    ray = Pilha.new("Rayovac")
    
    ray.apresentacao
    
    controle = Aparelho.new(ray)
    
    controle.ligado
    
    puts "A carga da pilha é de #{controle.pl.carga}%!"