Эту фразу можно встретить, читая о шаблонах проектирования.
Но я этого не понимаю, может ли кто-нибудь мне это объяснить?
oop
design-patterns
interface
software-design
ooad
never_had_a_name
источник
источник
Ответы:
Кодирование по отношению к интерфейсу означает, что клиентский код всегда содержит объект интерфейса, который предоставляется фабрикой. Любой экземпляр, возвращаемый фабрикой, будет иметь тип Интерфейс, который должен быть реализован любым классом-кандидатом фабрики. Таким образом, клиентская программа не заботится о реализации, а подпись интерфейса определяет, какие все операции могут быть выполнены. Это можно использовать для изменения поведения программы во время выполнения. Это также помогает вам писать гораздо лучшие программы с точки зрения обслуживания.
Вот вам простой пример.
РЕДАКТИРОВАТЬ
Я обновил приведенный выше пример и добавил абстрактный
Speaker
базовый класс. В этом обновлении я добавил функцию «SayHello» для всех выступающих. Все выступающие говорят «Hello World». Так что это общая черта с аналогичной функцией. Обратитесь к диаграмме классов, и вы обнаружите, что интерфейсSpeaker
реализации абстрактного классаISpeaker
помечаетсяSpeak()
как абстрактный, что означает, что каждая реализация Speaker отвечает за реализациюSpeak()
метода, поскольку он варьируется отSpeaker
доSpeaker
. Но все выступающие единодушно говорят «Привет». Итак, в абстрактном классе Speaker мы определяем метод, который говорит «Hello World», и каждаяSpeaker
реализация будет наследовать этотSayHello()
метод.Рассмотрим случай, когда
SpanishSpeaker
нельзя сказать «Привет», поэтому в этом случае вы можете переопределитьSayHello()
метод для говорящего по-испански и вызвать соответствующее исключение.И мы могли бы добиться такого поведения, просто добавив базовый абстрактный класс Speaker и немного изменив его в реализации Each, оставив исходную программу без изменений. Это желательная функция любого приложения, которая делает ваше приложение легко обслуживаемым.
источник
List
качестве типа a , вы все равно можете предполагать, что произвольный доступ выполняется быстро, многократно вызываяget(i)
.Думайте об интерфейсе как о контракте между объектом и его клиентами. То есть интерфейс определяет, что может делать объект, и сигнатуры для доступа к этим вещам.
Реализации - это фактическое поведение. Скажем, например, у вас есть метод sort (). Вы можете реализовать QuickSort или MergeSort. Это не должно иметь значения для клиентского кода, вызывающего sort, до тех пор, пока интерфейс не изменяется.
Такие библиотеки, как Java API и .NET Framework, интенсивно используют интерфейсы, потому что миллионы программистов используют предоставленные объекты. Создатели этих библиотек должны быть очень осторожны, чтобы не изменить интерфейс к классам в этих библиотеках, потому что это повлияет на всех программистов, использующих библиотеку. С другой стороны, они могут менять реализацию сколько угодно.
Если, как программист, вы кодируете вопреки реализации, то как только она меняет, ваш код перестает работать. Итак, подумайте о преимуществах интерфейса следующим образом:
источник
Это означает, что вы должны попытаться написать свой код так, чтобы он напрямую использовал абстракцию (абстрактный класс или интерфейс), а не реализацию.
Обычно реализация внедряется в ваш код через конструктор или вызов метода. Итак, ваш код знает об интерфейсе или абстрактном классе и может вызывать все, что определено в этом контракте. Поскольку используется реальный объект (реализация интерфейса / абстрактного класса), вызовы работают с объектом.
Это подмножество
Liskov Substitution Principle
(LSP), LSOLID
принципов.Примером в .NET будет код с
IList
вместоList
илиDictionary
, поэтому вы можете использовать любой класс, которыйIList
взаимозаменяемо реализуется в вашем коде:Другой пример из библиотеки базовых классов (BCL) - это
ProviderBase
абстрактный класс - он предоставляет некоторую инфраструктуру и, что немаловажно, означает, что все реализации поставщика могут использоваться взаимозаменяемо, если вы кодируете против него.источник
Если бы вам пришлось писать класс автомобилей в эпоху Combustion-Car, то велика вероятность, что вы бы реализовали oilChange () как часть этого класса. Но когда появятся электромобили, у вас возникнут проблемы, так как в этих автомобилях не требуется замена масла и нет никаких дополнительных приспособлений.
Решение проблемы состоит в том, чтобы иметь интерфейс performMain maintenance () в классе Car и скрывать детали внутри соответствующей реализации. Каждый тип Car будет предоставлять свою собственную реализацию для performMain maintenance (). Все, с чем вам, как владельцу Автомобиля, приходится иметь дело, - это выполнитьMain maintenance () и не беспокоиться об адаптации при ИЗМЕНЕНИИ.
Дополнительное объяснение: вы - автовладелец, у которого несколько машин. Вы создаете услугу, которую хотите передать на аутсорсинг. В нашем случае мы хотим передать обслуживание всех автомобилей на аутсорсинг.
Вам не нужно беспокоиться о привязке типа автомобиля к поставщику услуг. Вы просто указываете, когда хотите запланировать обслуживание, и вызываете его. Соответствующая сервисная компания должна вмешаться и выполнить работы по техническому обслуживанию.
Альтернативный подход.
Вы вызываете работу и делаете ее сами. Здесь вы будете выполнять соответствующие работы по техническому обслуживанию.
В чем обратная сторона второго подхода? Возможно, вы не являетесь экспертом в поиске лучшего способа обслуживания. Ваша задача - водить машину и получать от нее удовольствие. Не заниматься его поддержанием.
В чем обратная сторона первого подхода? Есть накладные расходы на поиск компании и т. Д. Если вы не компания по аренде автомобилей, это может не стоить усилий.
источник
Это утверждение о сцеплении. Одна из возможных причин использования объектно-ориентированного программирования - повторное использование. Так, например, вы можете разделить свой алгоритм между двумя взаимодействующими объектами A и B. Это может быть полезно для последующего создания другого алгоритма, который может повторно использовать тот или иной из двух объектов. Однако, когда эти объекты общаются (отправляют сообщения - вызывают методы), они создают зависимости друг от друга. Но если вы хотите использовать одно без другого, вам нужно указать, что должен делать другой объект C для объекта A, если мы заменим B. Эти описания называются интерфейсами. Это позволяет объекту A без изменений связываться с другим объектом, полагаясь на интерфейс. В упомянутом вами заявлении говорится, что если вы планируете повторно использовать какую-то часть алгоритма (или, в более общем плане, программу), вы должны создавать интерфейсы и полагаться на них,
источник
Как говорили другие, это означает, что ваш вызывающий код должен знать только об абстрактном родителе, а НЕ о фактическом реализующем классе, который будет выполнять эту работу.
Что помогает понять это, так это ПОЧЕМУ вы всегда должны программировать интерфейс. Есть много причин, но две из самых простых для объяснения:
1) Тестирование.
Скажем, у меня есть весь код моей базы данных в одном классе. Если моя программа знает о конкретном классе, я могу проверить свой код, только действительно запустив его для этого класса. Я использую -> для обозначения «разговаривает с».
WorkerClass -> DALClass Однако давайте добавим интерфейс к этому миксу.
WorkerClass -> IDAL -> DALClass.
Таким образом, DALClass реализует интерфейс IDAL, и рабочий класс вызывает ТОЛЬКО через него.
Теперь, если мы хотим написать тесты для кода, мы могли бы вместо этого создать простой класс, который просто действует как база данных.
WorkerClass -> IDAL -> IFakeDAL.
2) Повторное использование
Следуя приведенному выше примеру, допустим, мы хотим перейти с SQL Server (который использует наш конкретный DALClass) на MonogoDB. Это потребует серьезной работы, но НЕ если мы запрограммированы на интерфейс. В этом случае мы просто пишем новый класс БД и меняем (через фабрику)
WorkerClass -> IDAL -> DALClass
в
WorkerClass -> IDAL -> MongoDBClass
источник
интерфейсы описывают возможности. при написании императивного кода говорите о возможностях, которые вы используете, а не о конкретных типах или классах.
источник