Есть ли смысл в интерфейсах на динамических языках? - PullRequest
24 голосов
/ 18 сентября 2008

В статических языках, таких как Java, вам нужны интерфейсы, потому что в противном случае система типов просто не позволит вам делать определенные вещи. Но в динамических языках, таких как PHP и Python, вы просто берете преимущество утка-печатка .

PHP поддерживает интерфейсы. У Руби и Питона их нет. Таким образом, вы можете жить счастливо без них.

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

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

Ответы [ 17 ]

17 голосов
/ 18 сентября 2008

Я думаю об этом больше как уровень удобства. Если у вас есть функция, которая принимает «подобный файлу» объект и вызывает только метод read (), то неудобно - даже ограничивать - заставлять пользователя реализовывать некоторый интерфейс File. Так же просто проверить, есть ли у объекта метод чтения.

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

10 голосов
/ 18 сентября 2008

Да, есть точка

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

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

9 голосов
/ 18 сентября 2008

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

Эта концепция хорошо переносится на динамические языки. В зависимости от вашего определения слова «динамический», конечно, это даже включает Objective-C, который довольно широко использует протоколы в Какао.

В Ruby вы можете спросить, отвечает ли объект на заданное имя метода. Но это довольно слабая гарантия того, что он будет делать то, что вы хотите, особенно с учетом того, как мало слов используется снова и снова, полная подпись метода не учитывается и т. Д.

В Ruby я могу спросить

object.respond_to? :sync

Так что, да, у него есть метод с именем "sync", что бы это ни значило.

В Objective-C я мог бы спросить что-то похожее, т. Е. «Выглядит ли это / гуляет / крякает как что-то, что синхронизирует?»:

[myObject respondsToSelector:@selector(sync)]

Еще лучше, ценой некоторого многословия, я могу спросить что-то более конкретное, то есть "выглядит ли это / гуляет / крякает как нечто, синхронизирующееся с MobileMe?":

[myObject respondsToSelector:@selector(sync:withMobileMeAccount:)]

Это утка, печатающая до уровня вида.

Но действительно спросить объект, обещает ли он реализовать синхронизацию с MobileMe ...

[receiver conformsToProtocol:@protocol(MobileMeSynchronization)]

Конечно, вы могли бы реализовать протоколы, просто проверив наличие ряда селекторов, которые вы считаете определением протокола / утки, и достаточно ли они конкретны. В какой момент протокол является просто аббревиатурой для большого количества некрасивых responseds_to? запросы и некоторые очень полезные синтаксические сахара для использования компилятором / IDE.

Интерфейсы / протоколы - это еще одно измерение метаданных объекта, которое можно использовать для реализации динамического поведения при обработке этих объектов. В Java компилятор просто требует такого рода вещей для обычного вызова метода. Но даже динамические языки, такие как Ruby, Python, Perl и т. Д., Реализуют понятие типа, которое выходит за рамки просто «на какие методы реагирует объект». Отсюда и ключевое слово класса. Javascript - единственный действительно широко используемый язык без этой концепции. Если у вас есть классы, то интерфейсы тоже имеют смысл.

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

Кроме того, кто-то еще упомянул миксин. Рубиновые миксины - это способ обмена кодом - например, они связаны с реализацией класса. Интерфейсы / протоколы о интерфейсе класса или объекта. Они действительно могут дополнять друг друга. У вас может быть интерфейс, который определяет поведение, и один или несколько миксинов, которые помогают объекту реализовать такое поведение.

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

4 голосов
/ 18 сентября 2008

Если у вас нет жестких ограничений безопасности (поэтому никто не получит доступ к вашим данным так, как вы этого не хотите), и у вас есть хорошая документация или хорошо обученные кодеры (поэтому им не нужен интерпретатор / компилятор, чтобы сказать им что делать) значит нет, бесполезно.

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

3 голосов
/ 18 сентября 2008

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

3 голосов
/ 18 сентября 2008

У меня сложилось впечатление, что Python не имеет интерфейсов . Насколько я знаю, в Python вы не можете принудительно реализовать метод во время компиляции, потому что это динамический язык.

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

В Python также есть Mixins, так что вы можете создать класс Interface, определив Mixin, имеющий pass для каждой реализации метода, но на самом деле это не дает особой ценности.

2 голосов
/ 18 сентября 2008

Python 3000 будет иметь Абстрактные базовые классы . Стоит прочитать.

2 голосов
/ 18 сентября 2008

В таком языке, как PHP, где несуществующий вызов метода приводит к фатальной ошибке и приводит к отказу всего приложения, тогда интерфейсы yes имеют смысл.

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

2 голосов
/ 18 сентября 2008

Рене, пожалуйста прочитайте мой ответ на вопрос "Лучшие практики для проектирования больших систем на динамическом языке" здесь на StackOverflow. Я обсуждаю некоторые преимущества предоставления свободы динамических языков для экономии усилий при разработке и облегчения введения новых программистов в проект. При правильном использовании интерфейсы значительно способствуют написанию надежного программного обеспечения.

1 голос
/ 18 сентября 2008

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

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

Мне, однако, нравятся некоторые преимущества строгой типизации - прежде всего, я фанат раннего обнаружения ошибок. Я пытаюсь использовать "интерфейсное" абстрактное определение суперкласса.

class InterfaceLikeThing( object ):
    def __init__( self, arg ):
        self.attr= None
        self.otherAttr= arg
    def aMethod( self ):
        raise NotImplementedError
    def anotherMethod( self ):
        return NotImplemented

Это формализует интерфейс - в некотором смысле. Это не дает абсолютных доказательств того, что подкласс соответствует ожиданиям. Однако, если подкласс не может реализовать требуемый метод, мои модульные тесты не пройдут с очевидным NotImplemented возвращаемым значением или NotImplementedError исключением.

...