【问题标题】:Ruby interface classes?Ruby 接口类?
【发布时间】:2013-09-15 17:48:14
【问题描述】:

我有以下课程:

CachedObject
CachedObjectSource
CachedObjectDbSource < CachedObjectSource
CachedObjectDalliSource < CachedObjectSource

CachedObject 是从第三方 API 提取并存储在本地的非数据库对象。 CachedObject 将存储在数据库和 Dalli (memcache) 中,实时代码将 ping Dalli 源以获取对象的副本,如果对象不存在,Dalli 源将搜索数据库源并更新其缓存.所以它是一个嵌套调用,它要求 CachedObjectSource 的每个子类实现相同的一组方法。 IE,一个接口。

有没有办法编写 CachedObjectSource 类,使其子类必须实现接口?我是不是走错路了?

【问题讨论】:

  • 我认为 Ruby 的哲学是反对在类定义中对接口进行静态检查。如果您想确保CachedObjectSource 的子级实现相同的方法,也许Ruby 的方式是编写一个包含预期方法列表的单元测试,并验证每种类型的源responds_to? 的每个方法的实例在列表中。
  • @RoryO'Kane 当然,如果“每种类型的源”不是确定性的,那么单元测试方法就会失败。 (就像它可以从插件加载一样。)无论如何,对实现本身进行测试会更合适。
  • 你可以添加一个测试助手,它可以很容易地包含在测试子类的有效性中,类似于例如可用for ActiveModel

标签: ruby oop


【解决方案1】:

Ruby 不知道类似于 e.g. 的接口。爪哇。相反,Ruby 程序通常使用一种称为Duck Typing 的方法,这基本上意味着您可以向任何对象发送任何消息,然后该对象可以决定它是否会响应,即每个对象自行决定它具有哪些方法。

你能得到的最接近“接口”的东西是一个类(或模块),它实现了一个方法,但只引发了一个类似于这样的NotImplementedError

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

这样,该方法将存在并在调用时返回一个合理的错误,而不会在子类中被覆盖。然后,您应该编写一些文档,说明必须实现哪些子类才能符合要求。

【讨论】:

  • 您也可以通过不实现该方法来实现该方法,这会产生相同的错误。与其他语言相比,Ruby 倾向于更多地依赖单元测试来暴露此类问题,因为该语言本身没有任何严格的检查。
  • 当然,最后,这只是一个额外的提示,应该实现一个方法,NoMethodError 默认情况下与NotImplementedError 具有相同的含义。但是,该类的用户可以在代码中看到他们需要实现的内容并获得更清晰的错误消息。最后,这或多或少是显式与隐式的问题(而我更倾向于事物的显式方面)。
  • 如果您想提供有关必须实现的方法的更多信息,我喜欢使用以下行:fail NotImplementedError, "#{self.class}##{__method__} method must be implemented"
【解决方案2】:

您可以使用 gem interface
此 gem 模拟类似于 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

这个 gem 和 abstract gem 一起有用。
Abstract gem 提供抽象方法。

【讨论】:

    【解决方案3】:

    你也可以使用rint

    gem 'rint'

    CLI 自带的:

    $ rint c CachedObjectSourceInterface my_method

    将创建一个接口定义,但您也可以手动将其添加到任何类。然后您可以执行以下操作:

    class Instrument 
      implements CachedObjectSourceInterface
    end
    

    如果my_method 方法没有实现,它会抛出一个有意义的异常。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-01-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多