Ruby имеет Интерфейсы , как и любой другой язык.
Обратите внимание, что вы должны быть осторожны, чтобы не связать концепцию интерфейса , которая представляет собой абстрактную спецификацию обязанностей, гарантий и протоколов устройства с концепцией interface
, которая является ключевое слово в языках программирования Java, C # и VB.NET. В Ruby мы все время используем первое, но второго просто не существует.
Очень важно различать два. Что важно, это Интерфейс , а не interface
. interface
говорит вам почти ничего полезного. Ничто не демонстрирует это лучше, чем маркерные интерфейсы в Java, которые являются интерфейсами, которые вообще не имеют членов: просто взгляните на java.io.Serializable
и java.lang.Cloneable
; эти два interface
s означают очень разные вещи, но они имеют точно такую же подпись.
Итак, если два 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>
действительно сказано, что это, знаете ли, set ? Нигде! Точнее, в документации. На английском.
Практически во всех случаях interfaces
, как из Java, так и .NET, вся релевантная информация фактически находится в документах, а не в типах. Итак, если типы не говорят вам ничего интересного, зачем вообще их хранить? Почему бы не придерживаться только документации? И это именно то, что делает Руби.
Обратите внимание, что есть другие языки, на которых Interface действительно может быть описан значимым образом. Однако эти языки обычно не вызывают конструкцию, которая описывает Interface"interface
", они называют ее type
. В языке программирования с зависимой типизацией вы можете, например, выразить свойства, что функция sort
возвращает коллекцию той же длины, что и оригинал, каждый элемент в оригинале также находится в отсортированной коллекции и не больше элемент появляется перед меньшим элементом.
Итак, вкратце: у Ruby нет эквивалента Java interface
. Однако имеет эквивалент Java Interface и точно такой же, как в Java: документация.
Также, как и в Java, Приемочные тесты можно использовать для указания Интерфейс с.
В частности, в Ruby интерфейс объекта определяется тем, что он может делать , а не тем, чем является class
, или тем, что module
он смешивает в Любой объект, который имеет метод <<
, может быть добавлен. Это очень полезно в модульных тестах, где вы можете просто передать Array
или String
вместо более сложного Logger
, даже если Array
и Logger
не разделяют явное interface
друг от друга от того, что у них обоих есть метод с именем <<
.
Другим примером является StringIO
, который реализует тот же интерфейс , что и IO
, и, таким образом, большую часть интерфейса из File
, но без общего предка, кроме Object
.