Альтернативы абстрактным классам в Ruby? - PullRequest
9 голосов
/ 23 октября 2010

Я новичок в Ruby.Простой пример, что мне нужно:

class Animal
   abstract eat()

class Cat < Animal
   eat():
     implementation

class Dog < Animal
   eat():
     implementation

Другими словами, метод eat () должен быть обязательным для всех классов, расширяющих Animal.

В JAVA я бы просто использовалабстрактный класс, но после некоторого исследования я обнаружил, что многие люди не используют его в Ruby, и вместо него рекомендуются mixin / modules.

Однако я не понимаю, могут ли модули делать больше, чем просто включатьметоды сложения.Если быть точным, могут ли модули устанавливать требования к классам, какие методы они должны реализовывать (если да, пример был бы оценен)?

Подводя итог, что я должен использовать в этом случае, когда я хочу бытьуверены, что все классы одного типа имеют определенные методы и реализуют их по-своему?

Ответы [ 5 ]

19 голосов
/ 23 октября 2010

Используйте модуль, который определяет методы, которые должны быть реализованы.

module Animal
  def eat
    raise NotImplementedError
  end
end

class Cat
  include Animal

  def eat
    "Om nom nom"
  end
end

class Dog
  include Animal
end

c = Cat.new
c.eat # => "Om nom nom"

d = Dog.new
d.eat # => NotImplementedError
9 голосов
/ 23 октября 2010

Ruby не предлагает эту функциональность, нет. Вы несете ответственность за то, чтобы ваши классы реализовали то, что должны были реализовать.

Одной из причин того, что такая функциональность невозможна для Ruby, является то, что классы Ruby могут быть открыты повторно, и Ruby поддерживает загрузку произвольного кода во время выполнения, поэтому мы не можем знать, реализует ли класс определенный интерфейс, пока мы не попытаемся вызвать его .

Предположим, Animal должен иметь метод eat, и я делаю следующее:

class Cat < Animal
  def talk
    puts "meow"
  end
end

class Cat
  def eat
    puts "om nom nom"
  end
end

К концу этого файла Cat будет иметь определение eat, потому что классы Ruby могут открываться и изменяться несколько раз. Должен ли код ошибки после первого определения, потому что eat еще не был определен? Такая реализация повредит больше, чем поможет, поскольку повторное открытие классов является обычным явлением, даже если этот пример надуман. Должен ли он выдать ошибку после вызова метода eat и его не существует, поэтому мы можем быть уверены, что он определен, как только он нам понадобится? Что ж, если бы метод отсутствовал, то в любом случае это произошло бы . Интерпретатор никогда не сможет узнать, находится ли другое определение класса в пути, поэтому он никогда не сможет отключить вас, пока метод не будет вызван.

Короче говоря, суперклассы просто не могут требовать определения метода в Ruby, потому что динамическая природа классов противоречит такой цели.

Извините! Это место, где юнит-тестирование может пригодиться, однако, чтобы ваши подклассы делали то, что они должны делать, в любом случае.

2 голосов
/ 23 октября 2010

Yo может просто использовать пустые методы или заставить их выдавать ошибки, чтобы подклассы реализовывали их.

class Base
  def abstract_method
  end

  def mandatory_abstract_method
    raise NotImplementedError.new("You must implement this")
  end
end

Недостатком является то, что это будет применяться только при фактическом вызове метода.Ruby - динамический язык, и он не проверяется во время компиляции.

1 голос
/ 23 октября 2010

В Ruby нет эквивалента абстрактным классам.В основном это связано с тем, что Ruby динамически типизирован, что означает, что концепция абстрактных классов на самом деле не применима.

0 голосов
/ 30 мая 2016

Если вы действительно хотите реализовать абстракцию, тогда вы используете гем абстракции.

sudo gem install abstraction

Ссылочный пример Пример из Абстракция гем WIKI .

class Car
  abstract

  def go_forward
  # ...
 end
end

Car.new
> AbstractClassError: Car is an abstract class and cannot be instantiated

class Convertible < Car
  def door_count
    2
  end
end

class Sedan < Car
  def door_count
    4
  end
end

Convertible.new  # => #<Convertible:0x8fdf4>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...