Почему нам не нужны интерфейсы на динамических языках? - PullRequest
17 голосов
/ 17 июня 2010

Только из-за динамической типизации нам не требуется концепция интерфейсов (как в Java и C #) в python?

Ответы [ 9 ]

23 голосов
/ 17 июня 2010

interface в качестве ключевого слова и артефакта был введен Java 1 (и C # взял его оттуда), чтобы описать контракт, который должен придерживаться объект.

Но интерфейс всегда был ключевой частью объектно-ориентированной парадигмы и в основном он представляет методы, на которые должен реагировать объект. Java просто применяет этот механизм для обеспечения статической проверки типов.

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

 @i = 1;

Вам не нужно объявлять i типа FixNum, вы просто используете его. То же самое касается интерфейсов, они просто текут. Компромисс в том, что вы не можете проводить статическую проверку, а сбои отображаются только во время выполнения.

В другой руке Структурный тип (или статический тип утки, как я его называю: P), используемый языками как Go или Scala, дает лучшее из обоих миров.

1. См. Комментарий Даниэля Уорвикера о ключевом слове CORBA interface

5 голосов
/ 17 июня 2010

Мы не требуем их, но мы поддерживаем их. Проверьте Zope Interfaces (которые могут быть и используются за пределами Zope).

1 голос
/ 18 июня 2010

Perl имеет роли (или черты). Это больше, чем интерфейсы, в отличие от java-ролей perl, у нас может быть реализация, проверяющая эти ссылки для получения дополнительной информации о ролях perl

1 голос
/ 17 июня 2010

Одна ключевая вещь, по крайней мере, в некоторых динамических языках, которые делают явные интерфейсы более чем неловкими, это то, что динамические языки часто могут отвечать на сообщения (например, «вызовы методов»), о которых они не знают заранее, даже делая что-то.как создание методов на лету.Единственный реальный способ узнать, правильно ли объект ответит на сообщение, - отправить ему сообщение.Это нормально, потому что динамические языки считают, что лучше поддерживать такие вещи, чем статическую проверку типов;объект считается пригодным для использования в конкретном протоколе, поскольку «известно», что он может участвовать в этом протоколе (например, в силу того, что он передан другим сообщением).

1 голос
/ 17 июня 2010

Стоит отметить, что, вопреки тому, что многие люди скажут в качестве первого ответа, интерфейсы можно использовать не только для документирования «какие методы поддерживает класс». Грзенио затрагивает это своей формулировкой «реализовать то же поведение». Как конкретный пример этого, посмотрите на интерфейс Java Serializable. Он не реализует никаких методов; скорее он используется в качестве «маркера» для указания того, что класс можно безопасно сериализовать.

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

1 голос
/ 17 июня 2010

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

Динамические языки используют «типизацию утки», что означает, что метод просто ищется во время выполнения, и если он существует с правильной сигнатурой, он используется; в противном случае возникает ошибка во время выполнения. Если два объекта «крякают как утка», реализуя один и тот же метод, они могут быть заменяемыми. Таким образом, в языке нет явной необходимости связывать их через базовый класс или интерфейс.

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

0 голосов
/ 17 июня 2010

Динамические языки имеют тип Duck

Если он ходит как утка и крякает как утка, это должна быть утка

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

Другими словами, если вы подставляете объект для поддержки метода Delete (), вы можете просто использовать

obj.Delete()

, но если объект не поддерживает Delete (), вы получите ошибку времени выполнения. Языки со статической типизацией не позволят этого и выдадут ошибку времени компиляции. Таким образом, вы в основном торгуете типом safty против более быстрого времени разработки и гибкости.

Без интерфейсов вы можете сделать что-то подобное на статических языках:

void Save(MyBaseClass item)
{
    if (item.HasChanges)
        item.Save()
}

но для этого потребуется, чтобы каждый объект, который вы передаете этому методу, наследовал от MyBaseClass. Поскольку Java или C # не поддерживают муль-наследование, которое не очень гибкое, потому что, если ваш класс уже наследует другой класс, он также не может наследовать от MyBaseClass. Поэтому лучшим выбором было бы создать интерфейс ISavable и принять его в качестве входного параметра, чтобы гарантировать возможность сохранения элемента. Тогда у вас есть все лучшее: безопасность и гибкость.

public interface ISavable
{
    bool HasChanges {get;set;}
    void Save();
}

void Save(ISavable item)
{
    if (item.HasChanges)
        item.Save()
}

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

void Save(object item)
{
    if (item.HasChanges)
        item.Save()
}

Но опять же, у вас нет проверки времени компиляции и, возможно, вы получите ошибку времени выполнения, если кто-то использует ваш метод с несовместимым классом.

0 голосов
/ 17 июня 2010

В C # и Java интерфейсы - это просто абстрактные классы со всеми абстрактными методами.Они существуют, чтобы разрешить псевдо множественное наследование, фактически не поддерживая полноценное множественное наследование, и создает множественное наследование неоднозначности.

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

0 голосов
/ 17 июня 2010

Интерфейсы используются в статически типизированных языках для описания того, что два независимых друг от друга объекта «реализуют одинаковое поведение».В динамически типизированных языках неявно предполагается, что когда два объекта имеют метод с одинаковым именем / параметром, он делает одно и то же, поэтому интерфейсы бесполезны.

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