Почему люди в Ruby говорят, что им не нужны интерфейсы? - PullRequest
8 голосов
/ 31 октября 2011

Имеет ли ruby ​​что-то отличное от других языков ООП (например, PHP), что делает интерфейсы бесполезными?Есть ли какая-нибудь замена для этого?

Редактировать:

Некоторые пояснения:

  • На других языках (например, PHP) вы нене нужны интерфейсы (они не являются обязательными на уровне кода).Вы используете их, чтобы заключить договор, улучшить архитектуру программного обеспечения.Поэтому утверждение «в ruby ​​вам не нужны интерфейсы / в других языках вам нужны интерфейсы, потому что XXX» ложно.

  • Нет, миксины не являются интерфейсами, они совершенно разныевещь (PHP 5.4 реализует миксины).Вы даже использовали интерфейсы?

  • Да, PHP - это ООП.Языки развиваются, добро пожаловать в настоящее.

Ответы [ 7 ]

14 голосов
/ 31 октября 2011

Что ж, все согласны с тем, что когда объект передается в Ruby, он не проверяется типом. Интерфейсы в Java и PHP - это способ подтвердить, что объект соответствует определенному контракту или «типу» (так что что-то может быть Serializable, Authorizable, Sequential и все остальное, что вы хотите).

Однако в Ruby отсутствует формализованное понятие контракта, для которого интерфейсы будут выполнять какую-то значимую роль, поскольку соответствие интерфейса не проверяется в сигнатурах методов . См. Например, Enumerable. Когда вы смешиваете его с вашим объектом, вы используете его функциональность , в отличие от объявления , что ваш объект Enumerable. Единственное преимущество наличия вашего объекта Enumerable состоит в том, что, определив each(&blk), вы автоматически получаете map, select и друзей бесплатно. Вы можете прекрасно иметь объект, который реализует все методы, предоставляемые Enumerable, но не смешивается в модуле, и он все равно будет работать.

Например, для любого метода в Ruby, который ожидает IO-объект, вы могли бы передать что-то, что не имеет ничего , связанного с IO, и тогда оно взорвалось бы с ошибкой или - если вы реализовали Заглушка ввода / вывода правильно - она ​​будет работать нормально, даже если переданный вами объект не объявлен как "IO-ish".

Идея, лежащая в основе этого, заключается в том, что объекты в Ruby на самом деле не являются прославленными хеш-таблицами с наложенными на них тегами (которые затем имеют некоторые дополнительные теги, которые сообщают интерпретатору или компилятору, что этот объект имеет интерфейс X, поэтому он может использоваться в контексте Y), но закрытая сущность, отвечающая на сообщения. Поэтому, если объект отвечает на конкретное сообщение, он выполняет контракт, а если он не отвечает на это сообщение, то возникает ошибка.

Таким образом, отсутствие интерфейсов компенсируется частично наличием модулей (которые могут содержать функциональные возможности, к которым вы обращаетесь без выполнения каких-либо обещаний типа для вызывающего абонента / потребителя) и частично традицией передачи сообщений в отличие от типизированных диктов .

Вам следует посмотреть несколько презентаций Джима Вейриха, так как он широко затрагивает эту тему.

3 голосов
/ 05 мая 2013

Этот вопрос является своего рода открытым, но вот мое мнение:

Цель объявления интерфейса состоит из двух вещей:

  1. Объявите себя или своих коллегкакие методы должен иметь этот класс
  2. Объявите на своем компьютере, какие методы должен иметь этот класс

Если мы сначала выберем вторую цель, исходный код Ruby никогда не будет скомпилирован, поэтому никогда не будетвозможность проверить соответствие объявлению интерфейса и предупредить разработчика о любом несоответствии.Это означает, что если бы в 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.

2 голосов
/ 05 мая 2013

Я «человек с Ruby», и мне хотелось бы, чтобы интерфейсы или что-то вроде них.

Не для принудительного исполнения контракта - потому что принудительное выполнение чего-либо не очень Ruby, и в некотором смысле опровергает точку зрения.динамического языка, и в любом случае нет никакого шага «компиляции» для его применения - но для документирования контрактов, которые клиентские подклассы могут выбрать (или нет), хотя, если они решат не делать этого, они не смогут пожаловаться, если код не 'не работает).

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

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

Это не идеально, но это достаточно редкий случай, и он работает для меня.

2 голосов
/ 31 октября 2011

Поскольку 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, который реализуется как классом Duck, так и классом Bird.

0 голосов
/ 31 октября 2011

Зависит от того, что вы подразумеваете под интерфейсом.

Если под интерфейсом вы подразумеваете конкретный объект, который существует на вашем языке, который вы наследуете или реализуете, то нет, вы не используете интерфейсы на языке, таком как ruby.

Если вы имеете в виду интерфейс, поскольку в объектах есть какой-то хорошо документированный интерфейс, то да, конечно, у объектов все еще есть хорошо документированные интерфейсы, у них есть атрибуты и методы, которые вы ожидаете там.

I 'Я согласен, что интерфейсы - это то, что существует в вашем уме и документации, а не в коде как объекте.

0 голосов
/ 31 октября 2011

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

Просмотрите это тоже:

http://en.wikipedia.org/wiki/Duck_typing

0 голосов
/ 31 октября 2011

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...