Menu
Coddy logo textTech

Rozszerzanie obiektów

Część sekcji Programowanie obiektowe ścieżki Ruby w Coddy. Lekcja 28 z 57.

extend dodaje metody modułu do jednego obiektu zamiast do wszystkich instancji. Rozszerzenie klasy dodaje je do obiektu klasy, dzięki czemu stają się metodami klasowymi:

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

Wynik:

Dog has 2 methods

Moduł używany z extend może przechowywać stan w zmiennych instancji klasy. Każda klasa, która go rozszerza, otrzymuje własną kopię, jako zmienne instancji klasy:

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}"

Wynik:

2 1

extend działa również na pojedynczym obiekcie. Tylko ten obiekt zyskuje metody; pozostałe instancje jego klasy pozostają bez zmian, a is_a? zwraca true tylko dla rozszerzonego obiektu:

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)

Wynik:

car is shining
true
false

Dwa słowa kluczowe umieszczają metody tego samego modułu w różnych miejscach. include sprawia, że stają się one metodami instancji klasy, a extend sprawia, że stają się metodami jednego rozszerzanego obiektu:

class Order
  include Printable    # order.print_me       (każda instancja)
  extend Counted       # Order.record         (sama klasa)
end

item.extend(Shiny)     # item.polish          (tylko ten obiekt)
challenge icon

Wyzwanie

Łatwy

Uzupełnij moduł Registry, którego klasy używają za pomocą extend. register(name) dodaje nazwę do własnej listy klasy, przechowywanej w @entries (tworzonej przy pierwszym użyciu), i zwraca Plugin registered x; jeśli nazwa już się na niej znajduje, zwraca Plugin already has x. entries zwraca listę, a count jej rozmiar. Zarówno Plugin, jak i Theme rozszerzają Registry i przechowują oddzielne listy.

Dostarczony kod odczytuje wiersze plugin name lub theme name, wywołuje register dla pasującej klasy i wyświetla odpowiedź. Na koniec wyświetla plugins: a, b (2) oraz themes: ... albo none (0) dla pustej listy.

Twój kod umieść w plikach registry.rb, plugin.rb i theme.rb. main.rb zawiera dostarczony kod wejścia/wyjścia i nie można go edytować.

Spróbuj swoich sił

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

# Dostarczony kod wejścia/wyjścia: pozostaw go bez zmian
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 iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator Ruby online