Menu
Coddy logo textTech

Estendendo Objetos

Parte da seção Programação orientada a objetos do Journey de Ruby da Coddy. Lição 28 de 57.

extend adiciona os métodos de um módulo a um objeto, em vez de a todas as instâncias. Estender uma classe os adiciona ao objeto da classe, fazendo com que se tornem métodos de classe:

module Describable
  def describe
    "#{name} has #{instance_methods(false).size} methods"
  end
end

class Dog
  extend Describable

  def bark
    "Woof"
  end

  def sit
    "sits"
  end
end

puts Dog.describe

Saída:

Dog has 2 methods

Um módulo usado com extend pode manter o estado em variáveis de instância da classe. Cada classe que o estende obtém sua própria cópia, como variáveis de instância da classe:

module Counted
  def created
    @created ||= 0
  end

  def record
    @created = created + 1
  end
end

class Order
  extend Counted
end

class Invoice
  extend Counted
end

Order.record
Order.record
Invoice.record
puts "#{Order.created} #{Invoice.created}"

Saída:

2 1

extend também funciona em um único objeto. Somente esse objeto obtém os métodos; outras instâncias de sua classe permanecem inalteradas, e is_a? é true apenas para o objeto estendido:

module Shiny
  def polish
    "#{self} is shining"
  end
end

a = "car"
b = "bike"
a.extend(Shiny)
puts a.polish
puts a.is_a?(Shiny)
puts b.respond_to?(:polish)

Saída:

car is shining
true
false

As duas palavras-chave colocam os métodos do mesmo módulo em lugares diferentes. include os transforma em métodos de instância de uma classe, enquanto extend os transforma em métodos do único objeto que é estendido:

class Order
  include Printable    # order.print_me       (cada instância)
  extend Counted       # Order.record         (a própria classe)
end

item.extend(Shiny)     # item.polish          (apenas este objeto)
challenge icon

Desafio

Fácil

Complete o módulo Registry, que as classes usam com extend. register(name) adiciona um nome à própria lista da classe, mantida em @entries (criada no primeiro uso), e retorna Plugin registered x; um nome que já esteja nela retorna Plugin already has x. entries retorna a lista, e count, seu tamanho. Tanto Plugin quanto Theme estendem Registry e mantêm listas separadas.

O código fornecido lê linhas plugin name ou theme name, chama register na classe correspondente e imprime a resposta. Por fim, imprime plugins: a, b (2) e themes: ..., ou none (0) para uma lista vazia.

Seu código deve ficar em registry.rb, plugin.rb e theme.rb. main.rb contém o código fornecido de entrada/saída e não pode ser editado.

Experimente você mesmo

require_relative 'registry'
require_relative 'plugin'
require_relative 'theme'

# Código de entrada/saída fornecido: mantenha-o como está
input = []
while (line = gets)
  input << line.chomp
end
input.each do |line|
  kind, name = line.split
  target = kind == "plugin" ? Plugin : Theme
  puts target.register(name)
end
[["plugins", Plugin], ["themes", Theme]].each do |label, klass|
  list = klass.entries.empty? ? "none" : klass.entries.join(", ")
  puts "#{label}: #{list} (#{klass.count})"
end
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação orientada a objetos

Pratique por conta própria: Compilador de Ruby online