Утиная типизация
Часть раздела Объектно-ориентированное программирование путешествия по Ruby на Coddy. Урок 33 из 57.
Ruby не проверяет класс объекта перед вызовом метода; ему нужно лишь, чтобы у объекта был этот метод. «Если он ходит как утка и крякает как утка, значит, это утка». Это утиная типизация: классы, у которых нет общего суперкласса, всё равно можно использовать в одном и том же месте:
class Duck
def speak
"Quack"
end
end
class Robot
def speak
"Beep"
end
end
class Radio
def speak
"...news..."
end
end
[Duck.new, Robot.new, Radio.new].each { |thing| puts thing.speak }Вывод:
Quack
Beep
...news...Встроенные классы тоже участвуют. Метод, использующий только <<, работает с массивом, строкой или любым вашим объектом, в котором определён <<:
class Tally
attr_reader :count
def initialize
@count = 0
end
def <<(_item)
@count += 1
self
end
end
def export(items, target)
items.each { |item| target << item.to_s }
target
end
p export([1, 2], [])
p export([1, 2], +"")
puts export([1, 2, 3], Tally.new).countВывод:
["1", "2"]
"12"
3respond_to?(:name) проверяет, есть ли у объекта публичный метод, не вызывая его. Используй это, когда объект может поддерживать или не поддерживать дополнительную возможность:
class Printer
def print_page(text)
"printing #{text}"
end
end
class Scanner
end
[Printer.new, Scanner.new].each do |device|
if device.respond_to?(:print_page)
puts device.print_page("report")
else
puts "#{device.class} cannot print"
end
endВывод:
printing report
Scanner cannot printЕсли у объекта нет этого метода, вызов вызывает исключение NoMethodError, сообщение которого содержит имя метода и объекта. Утиная типизация основана на том, что каждый переданный объект отвечает на отправленные ему методы:
def loudest(things)
things.map(&:speak).max_by(&:size)
end
class Cat
def speak
"Meow"
end
end
puts loudest([Cat.new, Cat.new])
begin
loudest([Cat.new, 42])
rescue NoMethodError => e
puts e.message
endВывод:
Meow
undefined method `speak' for an instance of IntegerЗадание
ЛегкоЗавершите классы Printer и LineCounter, а также вспомогательную функцию export(items, target) в functions.rb. export отправляет каждый элемент в целевой объект с помощью target << item.to_s и возвращает целевой объект. Printer#<< выводит текст с номером строки, 1: text, и возвращает принтер. LineCounter#<< подсчитывает строки и символы и возвращает счётчик; его to_s возвращает 3 lines, 12 chars.
Предоставленный код считывает элементы, экспортирует их в массив (выводится с помощью p), в новую строку (выводится с помощью p), в Printer и в LineCounter (выводится с помощью puts).
Ваш код должен находиться в printer.rb, line_counter.rb и functions.rb. В main.rb находится предоставленный код ввода/вывода, и его нельзя редактировать.
Попробуйте сами
require_relative 'printer'
require_relative 'line_counter'
require_relative 'functions'
# Предоставленный код ввода/вывода: оставьте его как есть
input = []
while (line = gets)
input << line.chomp
end
p export(input, [])
p export(input, +"")
export(input, Printer.new)
puts export(input, LineCounter.new)
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Классы и объекты
Работа с файламиОпределение классовПеременные экземпляраМетоды и selfto_s и inspectПовторение — читательский билет4Инкапсуляция
Приватные методыЗащищённые методыПриватные сеттерыЗащита состоянияПовторение — торговый автомат7Полиморфизм и утиная типизация
ПолиморфизмУтиная типизацияАбстрактные методыcase и классыПовторение — способы оплаты10Шаблоны проектирования, часть 2
Делегирование с помощью ForwardableШаблон декоратораШаблон строителяШаблон состояния2Аксессоры и self
Чтение и записьПользовательские сеттерыself в методахИдентичность и равенствоПовторение — список контактов5Наследование
ПодклассыПереопределение методовВызов superis_a? и предкиПовторение — расчёт зарплаты сотрудников8Специальные методы
Равенство и хешированиеМетоды операторовИндексация и добавлениеПользовательские коллекцииПовторение — дроби11Проект: Управление библиотекой
Книги и читателиВыдача книг3Методы и переменные классов
Методы классовПеременные экземпляра классаКонстантыФабричные методыПовторение — коды купонов6Модули и примеси
Модули и includeРасширение объектовМодуль ComparableМодуль EnumerableПовторение — спортивная лига9Паттерны проектирования. Часть 1
Паттерн «Одиночка»Фабричный паттернПаттерн «Наблюдатель»Паттерн «Стратегия»Потренируйтесь самостоятельно: Онлайн-компилятор Ruby