ruby与其他OOP语言有什么不同(例如:PHP)会使接口变得无用吗?它有什么替代品吗?
编辑:
一些澄清:
在其他语言(例如:PHP)中,您不需要“接口”(在代码级别它们不是必需的)。您可以使用它们签订合同,以改进软件的架构。因此,肯定'在红宝石中你不需要接口/用其他语言你需要接口因为XXX'是假的。
不,mixins不是接口,它们是完全不同的东西(PHP 5.4实现了mixins)。你有没有使用过接口?
是的,PHP是OOP。语言不断发展,欢迎来到现在。
答案 0 :(得分:13)
嗯,这是一个共识,当一个对象在Ruby中传递时,它不是经过类型检查的。 Java和PHP中的接口是一种确认对象符合某个合同或“类型”的方式(因此某些内容可能是Serializable
,Authorizable
,Sequential
以及您想要的任何其他内容)。
然而,在Ruby中,没有形式化的合同概念,接口将履行一些有意义的角色,因为接口一致性未在方法签名中检查。例如,请参阅Enumerable
。当您将其混合到对象中时,您使用的是功能,而不是声明您的对象是Enumerable
。将对象设为Enumerable
的唯一好处是,定义each(&blk)
后您自动获得map
,select
和朋友。你可以完美地拥有一个实现Enumerable
提供的所有方法的对象,但不会在模块中混合,它仍然可以工作。
例如,对于Ruby中需要IO对象的任何方法,您可以输入一些 nothing 与IO相关的内容,然后它会因错误而爆炸,或者 - 如果您实现了您的IO存根正确 - 即使您传递的对象未被声明为“IO-ish”,它也能正常工作。
背后的想法来自这样一个事实:Ruby中的对象并不是真正美化的哈希表,并且标签被打到它们上(然后它有一些额外的标签告诉解释器或编译器这个对象有接口X因此它可以用于上下文Y)但是一个响应消息的封闭实体。因此,如果一个对象响应一个特定的消息,那么它将完成合同,如果它没有响应该消息 - 那么就会出现错误。
因此缺少接口可以部分地通过模块的存在来补偿(模块可以包含您在不对呼叫者/消费者做出任何类型承诺的情况下达到的功能),部分地通过消息传递的传统而不是键入的dicts来补偿
你应该观看Jim Weirich的一些演讲,因为他广泛接触过这个主题。
答案 1 :(得分:3)
这个问题有点开放,但这是我的看法:
接口声明的目的是两件事:
如果我们首先考虑第二个目的,那么永远不会编译Ruby源代码,因此永远不会有选项来验证与接口声明的一致性,并警告开发人员不遵守。这意味着如果Ruby有一些内置的接口支持,那么在运行时之前就没有选项可以验证一致性,因为缺少实现,应用程序将会崩溃。
回到第一个目的。代码可读性。这可能是有意义的,指定接口的正式Ruby约定可能会有所帮助。现在,您可能会使用注释或规范或 - 我可能更喜欢 - 声明模块包含来传达此信息。 E.g。
module Shippable
# This is an interface module. If your class includes this module, make sure it responds to the following methods
# Returns an integer fixnum representing weight in grams
def weight
raise NotImplementedError.new
end
# Returns an instance of the Dimension class.
def dimensions
raise NotImplementedError.new
end
# Returns true if the entity requires special handling.
def dangerous?
raise NotImplementedError.new
end
# Returns true if the entity is intended for human consumption and thereby must abide by food shipping regulations.
def edible?
raise NotImplementedError.new
end
end
class Product
include Shippable
end
实施此接口的一种方法是创建一个规范,创建包含Shippable
模块的每个类的实例,调用这四种方法并期望它们不会引发NotImplementedError
。
答案 2 :(得分:2)
由于ruby为duck-typed
,因此不需要单独的接口,但对象只需要实现常用方法。请看下面的“经典”示例:
class Duck
def move
"I can waddle."
end
end
class Bird
def move
"I can fly."
end
end
animals = []
animals << Duck.new
animals << Bird.new
animals.each do |animal|
puts animal.move
end
在此示例中,“interface”是move
方法,由Duck
和Bird
类实现。
答案 3 :(得分:2)
我是'红宝石人',我想要接口或类似的东西。
不强制执行合同 - 因为强制执行任何事情都不是Ruby,并且有点破坏动态语言的意义,无论如何没有“编译”步骤来强制执行 - 但是记录客户端子类可以签订的合同选择遵守(或不符合,但如果他们选择不这样做,他们不能抱怨,如果代码不起作用)。
当我遇到这个问题时,也就是说,当我编写一个类或模块时,我希望子类提供方法,我通常会记录我希望子类提供的方法,如下所示:
module Enumerable
def each
raise NotImplementedError, "Subclasses must provide this method"
end
end
这不太理想,但这是一个相当罕见的案例,对我有用。
答案 4 :(得分:0)
我相信这是因为Ruby是动态类型的,而其他语言是静态类型的。您需要在PHP中使用接口的唯一原因是在传递对象时使用类型提示。
答案 5 :(得分:-1)
答案 6 :(得分:-1)
取决于界面的含义。
如果by interface是指您继承或实现的语言中存在的具体对象,则不要使用ruby等语言中的接口。
如果你的意思是对象中的界面有一些记录良好的界面,那么当然,对象仍然有一个记录良好的界面,它们有你希望存在的属性和方法。
我同意接口是你脑海中存在的东西和文档,而不是作为对象的代码。