Все мы, программисты, наверное, слышали фразу под названием «Программируйте интерфейс, а не реализацию». Когда я впервые услышал эту фразу, она меня очень смутила, и мне потребовалось некоторое время, чтобы понять и применять этот принцип в моем ежедневном процессе разработки. Большинство людей или онлайн-ресурсов, с которыми я консультировался, не объясняли эту концепцию очень простым или понятным способом. Но поскольку я потратил так много времени на то, чтобы правильно понять эту концепцию, я надеюсь, что смогу немного облегчить вам понимание. Итак, давайте начнем с того, что вспомним одну из самых важных концепций ООП — «абстракцию».

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

Сбивает с толку, верно? Когда я читал это в первый раз, у меня в голове не зазвенело.

Просто забудьте об абстракции прямо сейчас и давайте сначала попробуем понять «инкапсуляцию».

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

«Абстракция — это тоже инкапсуляция, но она скрывает данные в более высокой степени (уровень класса)».

Все еще сбивает с толку? Не волнуйтесь. Я собираюсь объяснить это на реальных примерах, описывая реальные проблемы, с которыми мы сталкиваемся в нашей повседневной работе.

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

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

Скорее всего, у нас будет еще один сервис. Это нормально, но есть одна проблема с этим подходом: что, если этот человек продолжит приходить к вам с новыми требованиями? Каждый раз вам придется изменять существующий код (нарушая принцип открытия/закрытия SOLID), чтобы соответствовать вашим новым требованиям, например, мы внесли изменения в ProfileController и заменили DbUserService на файл FileUserService.

Теперь рассмотрим это решение…

Я создал UserProfileServiceInterface, и каждая служба реализует этот интерфейс. Кроме того, все эти службы используют общий контракт, согласно которому независимо от того, какой метод службы ProfileController::get получит, он должен иметь реализацию метода getProfiles. Этот пример наглядно демонстрирует концепцию абстракции. Мы инкапсулировали наши сервисы за UserProfileServiceInterface, и именно это я имел в виду, когда сказал: «абстракция — это тоже инкапсуляция, но в более высокой степени (уровень класса)». Это также демонстрирует идею «Программируйте интерфейс, а не реализацию».

Наконец, если у вас есть какие-либо мысли, которыми вы хотите поделиться по этой теме, я буду рад услышать от вас! Вы можете связаться со мной через Twitter или по электронной почте.

Спасибо за чтение!