Подтвердить что ты не робот

В Ruby, что эквивалентно интерфейсу в С#?

В настоящее время я пытаюсь изучить Ruby, и я пытаюсь понять, что он предлагает в плане инкапсуляции и контрактов.

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

Есть ли способ принудительного использования такого рода вещей в Ruby?

Спасибо

Простой пример того, что я имею в виду в С#:

interface IConsole
{
    int MaxControllers {get;}
    void PlayGame(IGame game);
}

class Xbox360 : IConsole
{
   public int MaxControllers
   {
      get { return 4; }
   }

   public void PlayGame(IGame game)
   {
       InsertDisc(game);
       NavigateToMenuItem();
       Click();
   }
}

class NES : IConsole
{
    public int MaxControllers
    {
        get { return 2; }
    }

   public void PlayGame(IGame game)
   {
       InsertCartridge(game);
       TurnOn();
   }
}
4b9b3361

Ответ 1

В рубине нет интерфейсов, поскольку ruby ​​- это динамически типизированный язык. Интерфейсы в основном используются, чтобы сделать разные классы взаимозаменяемыми без нарушения безопасности типа. Ваш код может работать с каждой консолью так долго, как ведет себя, как консоль, которая на С# означает реализацию IConsole. "duck typing" - это ключевое слово, которое вы можете использовать, чтобы догнать язык динамических языков для решения этой проблемы.

Далее вы можете и должны написать модульные тесты для проверки поведения вашего кода. Каждый объект имеет метод respond_to?, который вы можете использовать в своем утверждении.

Ответ 2

Ruby имеет интерфейсы, как и любой другой язык.

Обратите внимание, что вы должны быть осторожны, чтобы не сблизить концепцию интерфейса, которая является абстрактной спецификацией обязанностей, гарантий и протоколов блока с концепцией interface, которая является ключевым словом в Java, Языки программирования С# и VB.NET. В Ruby мы все время используем первое, но последнего просто не существует.

Очень важно различать два. Что важнее Интерфейс, а не interface. interface говорит вам почти ничего полезного. Ничто не демонстрирует это лучше, чем интерфейсы маркера в Java, которые являются интерфейсами, в которых нет участников: просто взгляните на java.io.Serializable и java.lang.Cloneable; эти два interface означают совсем другие вещи, но они имеют точно такую ​​же подпись.

Итак, если два interface, которые означают разные вещи, имеют одну и ту же подпись, что именно означает interface, гарантируя вам?

Еще один хороший пример:

interface ICollection<T>: IEnumerable<T>, IEnumerable
{
    void Add(T item);
}

Что такое интерфейс System.Collections.Generic.ICollection<T>.Add?

  • что длина коллекции не уменьшается
  • что все элементы, которые были в коллекции ранее, все еще там
  • что item находится в коллекции

И какой из них действительно отображается в interface? Никто! В interface нет ничего, что говорит о том, что метод Add должен даже вообще добавлять, он может просто удалить элемент из коллекции.

Это вполне допустимая реализация этого interface:

class MyCollection<T>: ICollection<T>
{
    void Add(T item)
    {
        Remove(item);
    }
}

Другой пример: где в java.util.Set<E> действительно ли он говорит, что это, знаете ли, набор? Нигде! Точнее, в документации. На английском языке.

В почти всех случаях interfaces, как с Java, так и с .NET, вся соответствующая информация фактически находится в документах, а не в типах. Итак, если типы вообще не говорят вам ничего интересного, зачем их вообще держать? Почему бы не придерживаться только документации? И это именно то, что делает Ruby.

Обратите внимание, что существуют другие языки, на которых интерфейс действительно можно описать значимым образом. Однако эти языки обычно не называют конструкцию, которая описывает интерфейс "interface", они называют его type. На языке программирования, зависящем от языка, вы можете, например, выразить свойства, которые функция sort возвращает коллекцию той же длины, что и оригинал, что каждый элемент, который находится в оригинале, также находится в сортированной коллекции и что больше элемент появляется перед меньшим элементом.

Итак, короче: Ruby не имеет эквивалента Java interface. Тем не менее, он имеет эквивалент Java-интерфейса, и он точно такой же, как в Java: documentation.

Кроме того, как и в Java, тесты Acceptance Tests могут также использоваться для указания интерфейсов.

В частности, в Ruby интерфейс объекта определяется тем, что он может делать, а не тем, что class является, или чем он смешивается. module он смешивает. Любой объект, который имеет метод <<, может быть прилагается. Это очень полезно в модульных тестах, где вы можете просто передать Array или String вместо более сложного Logger, хотя Array и Logger не разделяют явный interface из того, что они оба имеют метод под названием <<.

Другим примером является StringIO, который реализует тот же интерфейс, что и IO, и, следовательно, большая часть интерфейса File, но без совместного использования какого-либо общего предка, кроме Object.

Ответ 3

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

Ruby, с другой стороны:

  • Является динамически типизированным языком с "утиным набором", поэтому, если вы хотите вызвать метод foo для двух объектов, им не нужно ни наследовать один и тот же класс предков, ни реализовать тот же интерфейс.
  • Поддерживает множественное наследование посредством концепции mixins, опять же нет необходимости в интерфейсах здесь.

Ответ 4

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

Существует драгоценный камень, называемый Handshake, который может выполнять неофициальные контракты, если вам это действительно нужно.

Ответ 5

Ruby использует концепцию модулей как интерфейс (kinda) для интерфейсов. Шаблоны проектирования в Ruby имеют множество действительно отличных примеров различий между двумя концепциями и почему Ruby выбирает более гибкую альтернативу интерфейсам.

http://www.amazon.com/Design-Patterns-Ruby-Russ-Olsen/dp/0321490452

Ответ 6

У Йорга хорошая точка, рубин имеет интерфейсы, а не ключевое слово. Читая некоторые ответы, я думаю, что это негатив в динамических языках. Вместо того, чтобы использовать интерфейс через язык, вы должны создавать модульные тесты вместо того, чтобы не использовать методы catch компилятора. Это также затрудняет понимание метода понимания, так как вам нужно выследить, что такое объект, когда вы пытаетесь его вызвать.

Возьмем в качестве примера:

def my_func(options)
  ...
end

Если вы посмотрите на эту функцию, вы не знаете, какие параметры и какие методы или свойства она должна вызывать, не обследуя модульные тесты, другие места, которые она вызывается, и даже смотрите на метод. Хуже того, метод может даже не использовать эти параметры, но передавать его другим методам. Зачем писать модульные тесты, если это должно быть уловлено компилятором. Проблема в том, что вы должны писать код по-другому, чтобы выразить этот недостаток в динамических языках.

Существует одна сторона этого, но динамические языки программирования - это FAST для написания фрагмента кода. Мне не нужно писать какое-либо объявление интерфейса, а позже я могу использовать новые методы и параметры, не выходя из интерфейса, чтобы разоблачить его. Компромиссы - это скорость для обслуживания.