2011-10-31 224 views
6

红宝石是否有其他OOP语言(例如:PHP)使接口无用?它有这种替代吗?为什么Ruby人说他们不需要接口?

编辑:

一些澄清:

  • 在其他语言(例如:PHP),你不 “需要” 的接口(他们是不是在代码级别强制)。您使用它们来签订合同,以改进软件的体系结构。因此,在Ruby中你肯定不需要接口/用你需要的其他语言接口,因为XXX'是错误的。

  • 不,mixins不是接口,它们是完全不同的东西(PHP 5.4实现了mixins)。你甚至使用过接口吗?

  • 是的,PHP是OOP。语言不断演变,欢迎来到现在。

+5

PHP是一种OOP语言? *轻笑* – NullUserException

+0

http://en.wikipedia.org/wiki/Mixin – robinjam

+0

PHP 5(我认为这是该版本)向PHP引入了OOP设计概念,但它并没有使它成为“OOP”语言。你现在可以编写OOP风格的PHP代码。 –

回答

0

我相信这是因为Ruby是动态类型的,而其他语言是静态类型的。您需要在PHP中使用接口的唯一原因是在传递对象时使用类型提示。

+0

可能是一个更具体的想法 - ruby​​不只是动态类型,它是鸭子类型。 – robinjam

+0

虽然我们正在拆分头发,鸭子打字是一种特定类型的动态打字;) –

+1

我知道,这就是为什么我说它不是_just_动态打字;)。它相关的原因是因为在ruby中它是一个对象当前的一组方法和属性,而不是它的超类或接口,它决定了它的“类型”。 – robinjam

-1

要看你通过接口的意思。

如果通过接口指的是您的语言中存在的具体对象,您从中继承或实现,那么您不使用像Ruby这样的语言中的接口。

如果你的意思是接口在对象中有一些记录良好的接口,那么当然是,对象仍然有一个良好的文档接口,他们有你期望在那里的属性和方法。

我同意接口是存在于你的头脑和文档中的,而不是作为对象存在于代码中。

+0

是的,我知道你不使用Ruby中的接口,但我想知道为什么(除了该功能不可用) – HappyDeveloper

+0

@HappyDeveloper哦,我想这不是obvouis。为什么让他们在代码中。它膨胀。头脑中有接口,在代码中不需要构造。除此之外,对于那些没有实现合适的输入系统的语言来说,这是一种肮脏的破解。你不需要一个接口,你需要一个在你的严格类型语言中定义明确的类型。 – Raynos

+0

如果我创建了类,我可以让他们在我的脑海里(有限的时间),但是我旁边的开发者呢?他们只需要猜测。接口有一个非常明确的作用,我不知道你的意思是“他们是黑客”。 Php也是动态的,但接口非常有用。例如,你将如何实现Bridge模式? – HappyDeveloper

3

由于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 

在这个例子中,“接口”是move方法,该方法是由DuckBird类既实现。

+0

在这里,我只能看到他们之间没有连接的两个类。这与其他语言有什么不同?在其他语言中,您可以做同样的事情,也可以添加合同(通过界面),尽管它不是强制性的 – HappyDeveloper

+0

@Happy,不同之处在于在(大多数)静态类型语言中,您必须使用显式接口来“连接“这两个班。 –

+0

@WayneConrad我知道我们没有谈论能够在这个线程中没有显式接口的情况下做到这一点的优缺点,但它会很好。他们对我而言并不是很明显。你能详细说明吗? – gabe

11

嗯,这是一个共识,当一个对象在Ruby中传递时,它不是经过类型检查的。 Java和PHP中的接口是一种确认对象符合某种合约或“类型”的方式(因此可能是Serializable,Authorizable,Sequential以及其他任何您想要的)。

但是,在Ruby中没有一个合同的正式概念,其中接口将履行一些有意义的作用,方法签名中未检查接口一致性。例如,参见Enumerable。当你将它混合到你的对象中时,你正在使用它的功能而不是声明你的对象是Enumerable。让您的对象为Enumerable的唯一好处是定义了each(&blk),您将自动获得map,select和朋友。您可以完美地拥有一个实现Enumerable提供的所有方法的对象,但不会混入模块中,它仍然可以工作。

例如,在Ruby中一个期望的IO对象,你可以在一些有什么做一个IO饲料,然后它会用一个错误或爆炸的任何方法 - 如果你正确地执行你的IO存根 - 即使传递的对象没有被声明为“IO-ish”,它也能正常工作。

这背后的想法来自这样一个事实,即Ruby中的对象并不是真正的荣耀的哈希表,其标签贴在它们上面(然后有一些额外的标签告诉解释器或编译器该对象具有接口X,因此它可以在上下文Y中使用),但是是一个封闭的实体来响应消息。所以如果一个对象响应一个特定的消息,它会满足合同,如果它没有回应那个消息 - 那么会出现错误。

因此,缺少接口的部分原因是模块的存在(它可以包含您在未对调用者/消费者做任何类型承诺的情况下达到的功能),部分由消息传递的传统而不是键入http://stardict.sourceforge.net/Dictionaries.php下载。

你应该看Jim Weirich的一些演讲,因为他广泛涉及这个主题。

+0

谢谢,我到家后会看到它们 – HappyDeveloper

3

这个问题是一种开放式的,但这里是我的看法:

接口声明的目的是两件事情:

  1. 声明你的未来的自己或同事什么方法这个类必须
  2. 声明到您的电脑用什么方法这个类必须有

如果我们先来第二个目的,Ruby源代码是从来没有组合物1因此,从来没有一种方法可以验证接口声明的一致性,并警告开发人员不符合要求。这意味着如果Ruby有一些内置的接口支持,它将不会有一个选项来验证一致性,直到运行时,应用程序无论如何都会崩溃,因为缺少实现。

回到第一个目的。代码可读性。这可能是有道理的,指定接口的正式Ruby约定可能会有所帮助。现在,您可能会使用注释或规范来进行交流,或者我可能会倾向于使用声明式模块包含。例如。

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一个规范的方式。

+0

只需要注意一点,您不需要使用'.new'显式实例化'NotImplementedErrors' - 您可以'引发NotImplementedError'并且它可以工作。 – Russell

+0

据我所知,接口对测试有好处,因此在测试过程中,您不需要注入所有服务,提供者等的真实实现。我知道您可以在Ruby测试期间创建存根,但是你必须记得然后去模拟所有应该被嘲笑的东西。但是编程中的“不得不记住”的东西并不是编写软件的好方法,特别是当你在一个团队中工作时。 – cryss

2

我是'Ruby人',我想要接口或类似的东西。

不强制执行合同 - 因为强制执行任何事情都不是Ruby,并且有点违背了动态语言,反正没有“强制执行”的“编译”步骤 - 但是要记录客户端子类的合同可以选择符合(或不符合,但如果他们选择不这样做,他们不能抱怨,如果代码不起作用)。

当我碰到这样的情况,即,当我在写一个类或模块我希望子类来提供,我通常会记录我希望子类来提供这样的方法方法:

module Enumerable 
    def each 
    raise NotImplementedError, "Subclasses must provide this method" 
    end 
end 

这并不理想,但这是一个相当罕见的情况,它适用于我。

相关问题