Интерфейсы интерфейса Ruby?

У меня есть следующие классы:

CachedObject
CachedObjectSource
CachedObjectDbSource < CachedObjectSource
CachedObjectDalliSource < CachedObjectSource

CachedObject - это объект без базы данных, который извлекается из стороннего API и хранится локально. CachedObject будет храниться как в базе данных, так и в Dalli (memcache), код реального времени будет пинговать источник Dalli для копии объекта, а источник Dalli будет искать источник базы данных и обновлять его кеш, если объект не существует, Таким образом, это вложенный вызов, который требует, чтобы каждый дочерний класс CachedObjectSource реализовал один и тот же набор методов. IE, интерфейс.

Есть ли способ написать класс CachedObjectSource, чтобы его дочерние классы реализовали интерфейс? Я иду об этом неправильно?

Ответ 1

Ruby не знает интерфейсы, подобные, например, Ява. Вместо этого в Ruby-программах обычно используется подход Duck Typing, который в основном означает, что вы можете отправлять любое сообщение любому объекту, который затем может решить, будет ли он отвечать к этому, т.е. каждый объект сам решает, какие методы он имеет.

Ближайшая вещь, которую вы можете получить в "интерфейсе", - это класс (или модуль), который реализует метод, но вызывает только NotImplementedError:

class CachedObjectSource
  def my_method
    raise NotImplementedError, "Implement this method in a child class"
  end
end

Таким образом, метод будет присутствовать и возвращать разумную ошибку при вызове без перезаписи в дочернем классе. Затем вы должны написать некоторую документацию, в которой ясно, какие дочерние классы должны внедряться для соответствия требованиям.

Ответ 2

Вы можете использовать gem interface.
Этот жемчуг эмулирует интерфейсы, аналогичные интерфейсам Java.
Например:

require 'interface'

MyInterface = interface{
  required_methods :foo, :bar, :baz
}

# Raises an error until 'baz' is defined
class MyClass
  def foo
    puts "foo"
  end

  def bar
    puts "bar"
  end

  implements MyInterface
end

Этот драгоценный камень, который полезен вместе с abstract gem.
Абстрактный камень содержит абстрактные методы.

Ответ 3

Вы также можете использовать rint

gem 'rint'

который поставляется с CLI:

$ rint c CachedObjectSourceInterface my_method

создаст определение интерфейса, но вы также можете добавить его вручную в любой класс. Затем вы можете сделать что-то вроде:

class Instrument 
  implements CachedObjectSourceInterface
end

и он выдает осмысленное исключение, если метод my_method не реализован.