Кодирование интерфейсов?

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

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

Исходя из вышесказанного:

  • Есть ли какие-либо заблуждения в моем понимании "кодирования для интерфейсов"?
  • Есть ли какие-либо преимущества кодирования для интерфейсов, которые я пропустил?

Спасибо.

Ответ 1

Только одна возможная коррекция:

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

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

List<String> l = new ArrayList<String>();
l.add("foo");
l.add("bar");

Если вы решили переключиться на другую реализацию List, код клиента работает без изменений:

List<String> l = new LinkedList<String>();

Это особенно полезно для скрытия деталей реализации, автоматического создания прокси и т.д.

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

Ответ 2

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

Неважно, будь то SanDisk или Titanium (даже не уверен, что это бренд), размер и цвет тоже не имеют значения. Фактически, единственное, что имеет значение, это то, что он не сломан (читается) и что он подключается к USB.

Ваш USB-накопитель соблюдает контракт, это, по сути, интерфейс. Можно предположить, что он выполняет некоторые основные обязанности:

  • Вилки в USB
  • Вызывается методом контракта CopyDataTo:

    public Интерфейс IUSB {  void CopyDataTo (строка somePath);//используется для копирования данных с миниатюрного диска на... }

  • Удерживается по методу контракта CopyDataFrom:

    public Интерфейс IUSB { void CopyDataFrom();//используется для копирования данных с вашего ПК на миниатюрный диск }

Возможно, эти методы не поддерживаются, но интерфейс IUSB - это просто контракт, которым должны следовать разработчики мини-дисков, чтобы обеспечить функциональность на разных платформах/поставщиках. Таким образом, SanDisk делает свой thumbdrive интерфейсом:

public class SanDiskUSB : IUSB
 {
  //todo: define methods of the interface here
 }

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

Ответ 3

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

Ответ 4

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

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

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

Сорт. Самое главное, это позволяет писать API, которые берут параметры с типами интерфейсов. Пользователи API могут затем передавать свои собственные классы (которые реализуют эти интерфейсы), и ваш код будет работать на этих классах, даже если они еще не существовали, когда они были написаны (например, java.util.Arrays.sort() способный сортировать все, что реализует Comparable, или поставляется с подходящим Comparator).

С точки зрения дизайна интерфейсы позволяют/обеспечивают четкое разделение между контрактами API и деталями реализации.

Ответ 5

Цель кодирования против интерфейсов - отделить ваш код от конкретной используемой реализации. То есть ваш код не будет делать предположений о конкретном типе, только интерфейс. Следовательно, конкретная реализация может быть обменена без необходимости корректировки вашего кода.

Ответ 6

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

Ответ 7

Думаю, вы могли намекнуть на это, но я считаю, что одним из самых больших преимуществ кодирования интерфейса является то, что вы нарушаете зависимость от конкретной реализации. Вы можете добиться ослабления связи и упростить передачу конкретных реализаций без изменения кода. Если вы просто учитесь, я бы посмотрел на различные шаблоны проектирования и как они решают проблемы путем кодирования на интерфейсы. Чтение книги Head First: Design Patterns действительно помогло мне щелкнуть.

Ответ 8

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

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

Это позволит вам растянуть свое мышление на полиморфизм следующим образом.

SoundMaker sm = new Duck();<br/>
SoundMaker sm1 = new ThunderousCloud();

sm.makeSound(); // quack, calls all sorts of stuff like larynx, etc.<br/>
sm1.makeSound(); // BOOM!, completely different operations here...