Этот вопрос уже имеет ответ здесь:
Я хочу укрепить свое понимание "кодирования для взаимодействия через интерфейс" с понятием. Насколько я понимаю каждый создает интерфейсы для формирования рисунка ожидаемой функциональности и затем реализует эти "контракты" в реальных классах. Для использования интерфейса, можно просто назвать методы на экземпляре реального класса.
Очевидное преимущество знает о функциональности, обеспеченной реальным классом, независимо от его определенной реализации.
На основе вышеупомянутого:
Спасибо.
Только одна возможная поправка:
Для использования интерфейса можно просто вызвать методы на экземпляре конкретного класса.
Вызов методов осуществляется по ссылке на интерфейс типа, в котором в качестве реализации используется конкретный класс:
List<String> l = new ArrayList<String>();
l.add("foo");
l.add("bar");
Если вы решили перейти на другую реализацию List, то код клиента работает без изменений:
List<String> l = new LinkedList<String>();
Это особенно удобно для сокрытия деталей реализации, автогенерации прокси и т.п.
Вы обнаружите, что такие фреймворки как spring и guice поощряют программирование на интерфейс. Это основа для таких идей как aspect-ориентированное программирование, автогенерируемые прокси для управления транзакциями и т.д.
.Кажется, ваше понимание верно. Ваш коллега только что заскочил к вам на стол и загрузил на флешку все последние фотографии рождественской вечеринки с участием вашего пьяного босса. Ваш коллега и вы не думаете дважды о том, как этот флеш-накопитель работает, для вас это черный ящик, но вы знаете, что он работает благодаря USB-интерфейсу.
Не имеет значения, SanDisk это или Titanium (даже не уверен, что это бренд), размер / цвет тоже не имеет значения. На самом деле, единственное, что имеет значение, это то, что он не сломан (читаемый) и что он подключается к USB.
Ваш USB флэш-накопитель соблюдает контракт, это, по сути, интерфейс. Можно предположить, что он выполняет некоторые очень основные обязанности:
Соблюдает контрактный метод CopyDataTo:
общедоступный интерфейс IUSB { void CopyDataTo(string somePath); // используется для копирования данных с диска с миниатюрами на... }
Выполняется договорным методом CopyDataFrom:
public Interface IUSB { void CopyDataFrom(); // используется для копирования данных с ПК на накопитель для миниатюр }
Ок, возможно, не эти методы, но интерфейс IUSB - это всего лишь контракт, который поставщики дисков с миниатюрами должны соблюдать, чтобы обеспечить функциональность на различных платформах/поставщиках. Поэтому SanDisk выпускает свой флеш-накопитель по интерфейсу:
public class SanDiskUSB : IUSB
{
//todo: define methods of the interface here
}
Ари, я думаю, что у вас уже есть четкое понимание (из того, как это звучит) того, как работают интерфейсы.
.Основным преимуществом является то, что использование интерфейса свободно соединяет класс с его зависимостями. После этого можно изменить класс или реализовать новую конкретную реализацию интерфейса, не меняя при этом классов, которые от него зависят.
.Целью кодирования против интерфейсов является отделение вашего кода от конкретной используемой реализации. То есть ваш код не будет делать предположений о конкретном типе, а только о интерфейсе. Следовательно, конкретная реализация может быть обменяна без необходимости корректировки вашего кода.
.Для использования интерфейса можно просто вызвать методы на экземпляре конкретного класса.
Обычно к типу интерфейса добавляется переменная, что позволяет получить доступ только к методам, определенным в интерфейсе.
Очевидным преимуществом является знание функциональности, предоставляемой конкретным классом, независимо от его специфической реализации.
Вроде того. Самое главное, это позволяет писать API, которые берут параметры с типами интерфейсов. Пользователи API затем могут передавать свои собственные классы (реализующие эти интерфейсы), и вы будете работать над этими классами, даже если их еще не существовало на момент написания (например, java.util.Arrays.sort(), имея возможность сортировать все, что реализует Comparable
или поставляется с подходящим Comparator
).
С точки зрения дизайна, интерфейсы позволяют/выполняют четкое разделение между контрактами API и деталями реализации.
.Вы не перечислили часть о том, как получить реализацию интерфейса, что важно. Если Вы явно инстанцируете реализующий класс конструктором, то Ваш код привязан к этой реализации. Вы можете использовать фабрику, чтобы получить экземпляр для вас, но тогда вы так же привязаны к фабрике, как и раньше к реализующему классу. Третья альтернатива - использовать инъекцию зависимостей, которая заключается в том, что фабрика подключает реализующий объект к объекту, который его использует, и в этом случае вы избежите наличия класса, который использует объект, привязанный к реализующему классу или фабрике.
.Я думаю, что вы могли намекнуть на это, но я считаю, что одним из самых больших преимуществ кодирования интерфейса является то, что вы разрушаете зависимость от конкретной реализации. Вы можете достичь свободной связи и облегчить переключение конкретных реализаций, не меняя большого количества кода. Если вы только учитесь, то я бы взглянул на различные шаблоны дизайна и на то, как они решают проблемы путем кодирования на интерфейсы. Читайте книгу Сначала голову: Шаблоны проектирования очень помогли мне.
Как я понимаю, создаются интерфейсы для разграничения ожидаемого функционала, а затем эти "контракты" реализуются в конкретных классах.
Единственный вид мутации, который я вижу в вашем мышлении - вы будете вызывать ожидаемые контракты, а не ожидаемую функциональность. Функциональность реализуется в конкретных классах. Интерфейс только констатирует, что вы сможете вызвать то, что реализует интерфейс с ожидаемыми сигнатурами метода. Функциональность скрыта от вызывающего объекта.
Это позволит растянуть мышление в полиморфизм следующим образом.
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...