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

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

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

PHP поддерживает интерфейсы. Ruby и Python их не имеют. Таким образом, вы можете спокойно жить без них.

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

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

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

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

Ответ 3

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

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

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

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

object.respond_to? :sync

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

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

[myObject respondsToSelector:@selector(sync)]

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

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

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

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

[receiver conformsToProtocol:@protocol(MobileMeSynchronization)]

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

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

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

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

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

Ответ 4

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

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

Ответ 5

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

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

У Python также есть Mixins, поэтому вы могли бы создать класс интерфейса, указав Mixin, имеющий pass для каждой реализации метода, но это не дает вам большой ценности.

Ответ 6

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

Ответ 7

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

Ответ 8

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

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

Ответ 10

Одно использование интерфейса Java - это разрешить сильно типизированные mixins в 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.

Ответ 11

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

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

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

Ответ 12

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

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

Ответ 13

Это похоже на то, что вам не нужны явные типы на динамически типизированном языке. Почему бы вам не сделать все "var" и документировать их типы в другом месте?

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

Ответ 14

как программист PHP, как я его вижу, интерфейс в основном используется в качестве контракта. Это позволяет вам сказать, что все, что использует этот интерфейс, ДОЛЖНО реализовать определенный набор функций.

Я не знаю, что все это полезно, но я нашел это немного камнем преткновения, пытаясь понять, что такое интерфейсы.

Ответ 15

Если вы считаете, что вам нужно, вы можете реализовать своего рода интерфейс с функцией, которая сравнивает методы/атрибуты объектов с данной сигнатурой. Вот очень простой пример:

file_interface = ('read', 'readline', 'seek')

class InterfaceException(Exception): pass

def implements_interface(obj, interface):
    d = dir(obj)
    for item in interface:
        if item not in d: raise InterfaceException("%s not implemented." % item)
    return True

>>> import StringIO
>>> s = StringIO.StringIO()
>>> implements_interface(s, file_interface)
True
>>> 
>>> fp = open('/tmp/123456.temp', 'a')    
>>> implements_interface(fp, file_interface)
True
>>> fp.close()
>>> 
>>> d = {}
>>> implements_interface(d, file_interface)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in implements_interface
__main__.InterfaceException: read not implemented.

Конечно, это не гарантирует очень много.

Ответ 16

В дополнение к другим ответам я просто хочу указать, что Javascript имеет ключевое слово instanceof, которое вернет true, если данный экземпляр находится где угодно в заданной цепочке прототипов объекта.

Это означает, что если вы используете свой "объект интерфейса" в цепочке прототипов для ваших "объектов реализации" (оба являются просто обычными объектами для JS), вы можете использовать instanceof, чтобы определить, реализует ли он его. Это не помогает аспекту правоприменения, но это помогает в аспекте полиморфизма, который является общим для интерфейсов.

Справочник по экземпляру MDN

Ответ 17

Остановить попытку написать Java на динамическом языке.