Что в Ruby эквивалентно интерфейсу в C#?

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

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

Есть ли способ применить такие вещи в 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();
   }
}

person fletcher    schedule 17.08.2010    source источник
comment
Отсутствие интерфейсов на языке кажется мне ужасным дизайнерским решением.   -  person Chris Marisic    schedule 17.08.2010
comment
В Ruby (и во всех языках) существуют интерфейсы — они просто не являются языковой функцией и, следовательно, компилятором не навязываются. Точно так же я мог бы сказать, что отсутствие целых чисел в языке кажется мне ужасным дизайнерским решением о C/C++/Java/C#/... - вам предоставлены инструменты для их создания, если это важно для вас. Но большую часть времени мы просто используем модульную арифметику на исчезающе маленьком подмножестве целых чисел, и наше программное обеспечение обычно работает нормально. Никто не умирает.   -  person Ken    schedule 18.08.2010
comment
Вы наверняка забыли дунуть на картридж перед тем, как вставить его...   -  person JJS    schedule 24.05.2017


Ответы (6)


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

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

person Zebi    schedule 17.08.2010
comment
По общему признанию, было бы полезно иметь возможность сказать [respond_to? ‹некоторый интерфейс›], где ‹некоторый интерфейс› означает некоторый набор операций. Для метода, который ожидает список объектов в качестве входных данных, поддерживающих ожидаемые операции (добавление, удаление, поиск, длину и т. д.), он может проверить, действительно ли его входные данные удовлетворяют этим требованиям, без необходимости проверки каждого из них. Рассматриваемый объект не должен быть объектом любого типа, просто поддерживать операции, объявленные этим интерфейсом. - person RHSeeger; 18.08.2010
comment
@myself - Кажется, вполне возможно определить response_to? type проверяет интерфейс (список методов), который просто перебирает методы в интерфейсе и возвращает true, если все они выполнены. - person RHSeeger; 18.08.2010
comment
Динамическая типизация не имеет к этому никакого отношения. Взгляните на php, он динамический и имеет интерфейсы. Почему люди, работающие с Ruby, не могут просто признать, что в языке отсутствуют некоторые функции? Отсутствует еще одна функция: подсказка типа. - person ChocoDeveloper; 23.11.2012
comment
@ChocoDeveloper Что? Вы можете просто реализовать нужные функции, если они вам действительно нужны/хотите. Ruby позволяет вам это сделать, PHP — нет. - person Sancarn; 03.06.2020

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

Обратите внимание, что вы должны быть осторожны, чтобы не смешивать концепцию Интерфейса, которая представляет собой абстрактную спецификацию обязанностей, гарантий и протоколов подразделения, с концепцией interface, которая является ключевым словом в Языки программирования Java, C# и 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, вся соответствующая информация содержится в документах, а не в типах. Так что, если типы все равно ничего интересного не говорят, зачем их вообще хранить? Почему бы не придерживаться только документации? И это именно то, что делает Руби.

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

Итак, вкратце: у Ruby нет эквивалента Java interface. Однако он действительно имеет эквивалент Интерфейса Java, и он точно такой же, как в документации Java:.

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

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

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

person Jörg W Mittag    schedule 17.08.2010
comment
Да, документация может описать, что должен делать класс, но ничего не гарантирует. С реализациями интерфейса вы можете быть уверены, что метод Add(item) по крайней мере присутствует. Выполняет ли он функцию, которую вы ожидаете от него, не имеет значения. Вы знаете, что если вы вызовете Add(item), он будет там и что-то сделает. Вышеизложенное звучит как расплывчатый религиозный аргумент. - person Ian Suttle; 13.03.2011
comment
@Ian, если ваше требование, которое вы хотите выполнить через интерфейс, состоит в том, чтобы убедиться, что у объекта есть метод Add, response_to? будет Ruby способ достижения этого. - person Tom Lianza; 13.07.2011
comment
Я согласен с Яном в том, что смысл интерфейса (в том виде, в каком он используется в таких языках, как Java) заключается в предоставлении удобного контракта для класса. Когда класс говорит, что он реализует интерфейс, я точно знаю, что будет метод Add, который я, скорее всего, смогу использовать для добавления вещей. Да, документация также говорит мне об этом, но это не главное. Я мог бы исказить код без пробелов и сказать, что прочитал документацию, чтобы понять, что делает этот класс. При этом комментарий Тома об использовании response_to? был бы путь. Но это не удобно. - person Kaushik Gopal; 03.05.2013
comment
Почему не удобно использовать response_to? Вы можете легко написать модульные тесты, которые просто проверяют интерфейс определенного класса. - person webpapaya; 22.01.2016
comment
@IanSuttle на самом деле лучше, чем это, потому что наличие «реализованного» метода указывает на обязательство реализовать его правильно: то есть, если он не делает то, что ожидается, то тип может быть объективно описан как «неправильный». Именно поэтому я невысокого мнения о структурной типизации, потому что намерение становится неявным, а не явный. Я думаю, что этот ответ полностью упускает из виду преимущества типизированных интерфейсов. - person VisualMelon; 15.02.2017

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

Руби, с другой стороны:

  1. Это динамически типизированный язык с «утиной типизацией», поэтому, если вы хотите вызвать метод foo для двух объектов, им не нужно ни наследовать один и тот же класс-предок, ни реализовывать один и тот же интерфейс.
  2. Поддерживает множественное наследование через концепцию примесей, опять же здесь нет необходимости в интерфейсах.
person Mladen Jablanović    schedule 17.08.2010
comment
композиция над наследованием - это путь. - person redigaffi; 08.09.2017

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

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

person Matchu    schedule 17.08.2010

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

https://rads.stackoverflow.com/amzn/click/com/0321490452

person Jed Schneider    schedule 17.08.2010
comment
У интерфейсов нет функциональности, у модулей есть. - person Marc-André Lafortune; 17.08.2010
comment
Интерфейс не является модулем. Оба компонуемые, но это все, что у них общего. - person mlibby; 13.02.2012

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

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

def my_func(options)
  ...
end

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

Однако у этого есть один положительный момент: динамические языки программирования позволяют БЫСТРЕЕ написать фрагмент кода. Мне не нужно писать какое-либо объявление интерфейса, и позже я могу создавать новые методы и параметры, не заходя в интерфейс, чтобы раскрыть его. Компромиссы - скорость для обслуживания.

person supermitsuba    schedule 30.05.2016
comment
пожалуйста, проверьте этот URL, это будет полезно для повышения качества - person Willie Cheng; 30.05.2016