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

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

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

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

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
26
0
3 784
17

Ответы 17

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

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

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

Да, в этом есть смысл

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

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

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

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

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

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

Rene Saarsoo 18.09.2008 15:21

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

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

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

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

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

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

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

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

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

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

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

supercat 16.05.2014 19:24

Одно из применений «интерфейса» 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.

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

joeforker 04.02.2009 21:17

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

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

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

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

object.respond_to? :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 и т. д., Реализуют понятие типа, выходящее за рамки того, «на какие методы отвечает объект». Отсюда ключевое слово class. Javascript - единственный действительно широко используемый язык без этой концепции. Если у вас есть классы, то и интерфейсы тоже имеют смысл.

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

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

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

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

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

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

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

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

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

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.

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

Прекратите пытаться писать Java на динамическом языке.

Что ж, я задал этот вопрос, потому что думал, что интерфейсы в PHP отчасти похожи на Java ... и мне действительно не нравится Java ... я не использовал ее годами.

Rene Saarsoo 06.04.2009 01:28

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

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

Ссылка на MDN instanceof

Другие вопросы по теме