Принцип разделения интерфейса

Разделение интерфейса . . . Хм, это звучит не так уж плохо, не так ли? Похоже, это как-то связано с разделением . . . МММ, разделяемся . . . межфазные границы. Мне просто интересно, где и как.

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

Все статьи серии

SOLID принципы на примере Laravel

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

Давайте рассмотрим очень распространенный и практичный пример. Каждый разработчик Laravel сталкивается с так называемым шаблоном репозитория в своей карьере, после чего они проводят следующие несколько недель, проходя через циклическую фазу максимумов и минимумов, и в конечном итоге отбрасывают шаблон. Почему? Во всех учебных пособиях, посвященных шаблону репозитория, рекомендуется создать общий интерфейс (называемый репозиторием), который будет определять методы, необходимые для доступа к данным или манипулирования ими. Этот базовый интерфейс может выглядеть примерно так:

interface Repository {
    public function getOne($id);
    public function getAll();
    public function create(array $data);
    public function update(array $data, $id);
    public function delete($id);
}

И теперь, для вашей User модели, вы должны создать UserRepository, который реализует этот интерфейс; затем, для вашей Customer модели, вы должны создать CustomerRepository, который реализует этот интерфейс

Так вот, в одном из моих проектов случилось так, что некоторые модели не должны были быть доступны для записи никому, кроме системы. Прежде чем вы начнете закатывать глаза, подумайте, что ведение журнала или ведение журнала аудита является хорошим реальным примером таких моделей “только для чтения”. Проблема, с которой я столкнулся , заключалась в том, что поскольку я должен был создавать репозитории, которые все реализовывали Repository интерфейс, скажем LoggingRepository, по крайней мере два метода в интерфейсе, update()и delete()не были мне полезны.

Да, быстрое решение состояло бы в том, чтобы реализовать их в любом случае и либо оставить их пустыми, либо вызвать исключение, но если бы полагаться на такие решения, то я бы вообще не следовал шаблону репозитория!

Хеееелп! Я застрял. :'(

Значит ли это, что во всем виноват паттерн репозитория?

Нет, вовсе нет!

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

Иногда эта идея выражается в том, что интерфейс является “жирным”, но это означает то же самое — интерфейс делает слишком много, и таким образом добавляет методы, которые бесполезны для некоторых классов, но все же эти классы вынуждены их реализовывать, что приводит к хрупкому, запутанному коду. Наш пример мог бы быть немного проще, но представьте себе, какой беспорядок может быть создан, когда несколько классов реализовали методы, которые они не хотели, или те, которые они хотели, но отсутствовали в интерфейсе.

Решение простое, и это также название обсуждаемого нами принципа: разделение интерфейса.

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

В Примере, который мы обсуждали, я мог бы создать два интерфейса вместо одного: ReadOnlyRespository (содержащий методы getOne()и getAll()) и WriteModifyRepository (содержащий остальные функции). Для обычных хранилищ, я бы тогда сказал class UserRepository implements ReadOnlyRepository, WriteModifyRepository { . .. }

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

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

Автор: Анкуш Тхакур 9 ноября 2020 года

Рейтинг
( 4 оценки, среднее 4.5 из 5 )
Maxyc Webber/ автор статьи
Мне 35 лет. Опыт профессиональной разработки 15 лет. Занимаюсь разработкой и поддержкой корпоративных систем автоматизации бизнеса, а также высоконагруженными проектами. Мне нравится решать нестандартные проблемы бизнеса. Имею опыт формирования команд под проект, налаживания процесса разработки, коммуникации программистов и заказчиков. Есть опыт работы с зарубежными заказчиками (ОАЭ, Польша, Германия, Швейцария).
Понравилась статья? Поделиться с друзьями:
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!:

Этот сайт использует Akismet для борьбы со спамом. Узнайте как обрабатываются ваши данные комментариев.