Выбор дизайна Java, позволяющий классам реализации явно объявлять реализуемый ими интерфейс, - это просто выбор дизайна. Безусловно, JVM была оптимизирована для этого выбора, и реализация другого варианта (скажем, структурная типизация Scala) может сейчас идти за дополнительную плату, если и до тех пор, пока не будут добавлены некоторые новые инструкции JVM.
Так, что именно означает выбор дизайна? Все сводится к семантике методов. Подумайте: семантически ли следующие методы одинаковы?
- draw (String graphicalShapeName)
- ничья (строковое имя пистолета)
- Draw (String PlayingCardName)
Все три метода имеют подпись draw(String)
. Человек может сделать вывод, что у него другая семантика, чем у имен параметров, или читая некоторую документацию. Есть ли способ для машины сказать, что они разные?
Выбор дизайна Java заключается в требовании, чтобы разработчик класса прямо заявил, что метод соответствует семантике предопределенного интерфейса:
interface GraphicalDisplay {
...
void draw(String graphicalShapeName);
...
}
class JavascriptCanvas implements GraphicalDisplay {
...
public void draw(String shape);
...
}
Нет сомнений, что метод draw
в JavascriptCanvas
предназначен для соответствия методу draw
для графического отображения. Если кто-то попытался передать предмет, который собирался вытащить пистолет, машина может обнаружить ошибку.
Выбор дизайна Go более либерален и позволяет определять интерфейсы после факта. Конкретный класс не должен объявлять, какие интерфейсы он реализует. Скорее, разработчик нового компонента карточной игры может объявить, что объект, поставляющий игральные карты, должен иметь метод, который соответствует подписи draw(String)
. Это имеет преимущество в том, что любой существующий класс с этим методом может использоваться без необходимости изменения его исходного кода, но недостаток в том, что класс может вытащить пистолет вместо игральной карты.
Проектный выбор языков типизации утки заключается в том, чтобы вообще отказаться от формальных интерфейсов и просто сопоставить сигнатуры методов. Любая концепция интерфейса (или «протокол») является чисто идиоматической, без прямой языковой поддержки.
Это всего лишь три из множества возможных вариантов дизайна. Три из них можно кратко описать так:
Java: программист должен явно объявить свое намерение, и машина проверит его. Предполагается, что программист может совершить семантическую ошибку (графика / пистолет / карта).
Go: программист должен объявить хотя бы часть своих намерений, но машине нужно меньше продолжать при проверке. Предполагается, что программист может совершить техническую ошибку (целое число / строка), но вряд ли допустит семантическую ошибку (графика / пистолет / карта).
Duck-typing: программисту не нужно выражать никаких намерений, и машине нечего проверять. Предполагается, что программист вряд ли допустит клерикальную или семантическую ошибку.
В этот ответ не входит рассмотрение вопроса о том, являются ли интерфейсы и типизация в целом адекватными для проверки канцелярских и семантических ошибок. Полное обсуждение должно было бы рассмотреть технологию компиляции во время сборки, методологию автоматизированного тестирования, компиляцию во время выполнения / горячую точку и множество других проблем.
Признано, что пример draw(String)
намеренно преувеличен, чтобы подчеркнуть. Реальные примеры будут включать более богатые типы, которые дадут больше подсказок для устранения неоднозначности методов.