Снова у нас впереди серия постов про зияющие глубины ООП-программирования. На этот раз представляю первый пост из этой новой серии «Твердые объектно-ориентированные принципы».
Это перевод серии одноименных статей от известного PHP-гуру, входящего в команду разработчиков Core PHP Team — Д. Кита Кейси (D. Keith Casey). И посвящен он важнейшим понятиям объектно-ориентированного дизайна — SOLID-принципам.
Хотелось бы верить, что известных понятий «слабая связность, высокая связность» достаточно, но когда вы действительно погружаетесь в эти концепции, вам становится ясно, что они носят скорее описательный, чем предписывающий характер.
Если вы хотите знать как применять их на практике изо дня в день в вашей разработке, вы должны будете погрузиться в SOLID-принципы, которые описывают 5 важных аспектов «хорошего» объектно-ориентированного дизайна.
Во-первых, это принцип единой ответственности или SRP (Single Responsibility Principle).
Если у вас есть класс, который управляет всеми аспектами одного процесса или одного объекта, это хорошо. Если же ваш класс также манипулирует другими объектами, или если это просто вместилище для кучи методов, — значит вы что-то делаете неправильно.
В нашем образцовом открытом проекте web2project есть класс Link
со следующими методами:
class CLink extends w2p_Core_BaseObject { public function __construct() { } public function loadFull(CAppUI $AppUI, $link_id) { } public function check() { } public function delete(CAppUI $AppUI) { } public function store(CAppUI $AppUI) { } public function hook_search() { } }
На первый взгляд можно сказать, что большинство из этих методов реализуют обычные CRUD-операции и взаимодействуют непосредственно только с объектом CLink
.
К сожалению, у нас есть еще один метод в данном классе:
public function getProjectTaskLinksByCategory _ (CAppUI $AppUI, $project_id = 0, $task_id = 0, _ $category_id = 0, $search = '') { }
Да, к сожалению, это настоящее имя метода... При взгляде на этот метод, одно лишь его имя уже говорит нам о том, как много всего здесь происходит.
В самом деле, у нас есть идентификаторы трех объектов в качестве входных данных, это означает что мы будем еще взаимодействовать как минимум с тремя другими объектами.
Если эти объекты когда-нибудь изменятся, мы, в конце концов, придем к антипаттерну «shotgun surgery», когда маленькое изменение в одной части кода вызывает небольшие изменения повсюду.
Такой код болезненно поддерживать даже короткое время.
Далее, существует еще один принцип: Открыто/Закрыто или OCP (Open/Closed Principle).
Возможно, вы слышали другую его формулировку: «Не хакай ядро». На практике этот принцип обеспечивается путем чрезвычайно избирательного использования ключевых слов «private» и «final».
Если вы размышляете, пометить ли что-либо как «private», остановитесь и переосмыслите свои цели. Вы просто пытаетесь ограничить использование сущности за пределами класса, или это действительно Единственно Верный Путь для выполнения вашей задачи?
Если первое, то возможно стоит использовать ключевое слово «protected». Это позволит расширить ваш класс и перегрузить методы в случае необходимости.
Далее, у нас есть принцип замещения Лискоy или LSP (Liskov Substitution Principle) и, если честно, это наиболее сложная вещь для моего понимания.
Примечания переводчика:
Есть также более строгие формулировки этого метода, например:
Формулировка № 1: eсли для каждого объекта o1 типа S существует объект o2 типа T, который для всех программ P определен в терминах T, то поведение P не измениться, если o1 заменить на o2 при условии, что S является подтипом T.
Формулировка № 2: подтипы должны быть заменяемы базовыми типами.
В характерных терминах это означает, что предопределенные условия метода/класса не могут быть усилены, постусловия не могут быть ослаблены, все возбуждаемые исключения должны быть в равной степени заменяемыми, и сигнатуры методов должны быть полностью совместимы.
Примечания переводчика:
Поясню на примере. Если для какой-нибудь функции родительского класса справедливо:
* пред-условие: item != null
* пост-условие: count = oldCount + 1
То для дочернего класса можно использовать:
* пред-условие: -
* пост-условие: count = oldCount + 1 && is_changed = true
Более подробно на моем блоге с этим принципом можно ознакомиться вот здесь.
Следующая концепция это принцип разделения интерфейса или ISP (Interface Segregation Principle).
Но с точки зрения непрофессионала, это намного проще. С течением времени и изменением требований наши системы растут. Без тщательного контроля наша иерархия классов растет и становится «грязной». Методы, которые имели смысл в начале проекта, не имеют такового в конце.
Взгляните на такой (надуманный) пример:
interface w2p_Interfaces_Authenticator { public function authenticate($username, $password); public function getUserId(); public function userExists(); public function changePassword(); }
Все эти методы связаны с пользовательской валидацией и аутентификацией, поэтому держать их вместе не лишено смысла. Объект, который будет расширять этот интерфейс, будет сильно связным, но посмотрите, например, на такой пример:
interface w2p_Interfaces_Modules_Setup { public function install(); public function upgrade($old_version); public function configure(); public function uninstall(); public function changeDisplayOrder(); }
Первые 4 метода имеют смысл в интерфейсе Setup
и описывают разумный жизненный цикл модуля. Последний метод имеет мало общего с установкой и скорее относится к уровню представления. Что-то здесь не так... Или, другими словами, у нас получился код «с запашком» (так называемый code smell).
Примечания переводчика:
Другая формулировка принципа: клиенты не должны зависеть от методов, которые они не используют
И наконец финальная концепция SOLID — принцип инверсии зависимостей или DIP (Dependency Inversion Principle).
В реальном мере это означает, что когда мы определяем зависимости класса, мы должны расчитывать на максимально широкий спектр возможностей.
В web2project часть нашей структуры классов выглядит так:
abstract class w2p_Core_BaseObject { public function __construct($table, $key, $module = '') {} public function load($oid = null, $strip = true) {} public function store($updateNulls = false) {} public function check() { } } class CProject extends w2p_Core_BaseObject { public function __construct() { } // load is inherited public function store(CAppUI $AppUI) { } public function check() { } } class CLink extends w2p_Core_BaseObject { public function __construct() { } // load is inherited public function store(CAppUI $AppUI) { } public function check() { } }
Т.к. у нас есть интерфесы, вместо того чтобы сделать наши контроллеры зависимыми от объектов CProject
или CLink
, мы можем взаимодействовать с w2p_Core_BaseObject
например таким образом:
class w2p_Controllers_Base { public function __construct(w2p_Core_BaseObject $object, $delete, $prefix, $successPath, $errorPath) { } }
Наш контроллер может взаимодействовать с любым из этих объектов, и ему все равно какой объект использовать. Это мощный механизм, который позволяет многоразовое использование контроллеров в нашей системе.
SOLID принципы сами по себе не дадут вам прекрасный OO-дизайн. Существуют обоснованные причины и ситуации когда их лучше не использовать и обойти, но это должно быть осознанное решение, а не прихоть или незнание. У нас может быть собственное мнение о том, когда и где их лучше применять. Мы должны оценить, что с их помощью мы приобретаем и улучшаем.
Нельзя просто взять и отметить чекбокс: «теперь мы поддерживаем SOLID».
~
Продолжение этой статьи читаем здесь, а для всех тех, кто хочет углубиться в принципы SOLID правильно ощущая их великую важность, как всегда выдам прямые ссылки на хороший дополнительный материал по теме.
Итак, ссылка номер раз — просто обалденный медиа-курс SOLID Principle Episodes, более понятная для большинства ссылка номер два — SOLID: TOP-5 архитектурных принципов + Принцип открытости/закрытости кода и какие трудности могут встать на пути (PHP). И завершающая ссылка номер три для чистых практиков: Шпаргалка по SOLID-принципам с примерами на PHP.
Также для закрепления темы хорошая презентация на русском:
Важно не забывать и про конкурирующие подходы, например читайте на нашем блоге про принципы GRASP. А пока ешьте больше шоколада (что как известно укрепляет мозг), а в перерывах, конечно же, читайте Блогератор.
4 комментария
http://121.127.250.74/home.php?mod=space&uid=2268324
Около 1000 независимых дилеров поддерживают каждую часть оборудования, обслуживая тысячи местных продаж, услуг, запасных частей и специалистов по аренде. Продавцы известны своей преданностью предоставлению отличного обслуживания клиентов для обеспечения долгой и надежной работы оборудования.
Интересное выражение встретил:)
Верность — это такая редкость и такая ценность. Это не врожденное чувство быть верным. Это решение.
Всем привет !!!
Заработайте на заказах снегурочек к новому году ! И проведите новый год с одной из них...!!!!)))
Снегурочка к Новому году!!!))) 2019 !!!
https://ficesaluke.com/in.htm?wm=849139262 - http://tds.clickcashmoney.com/bi?id=177880676&rnd=201001211952
Hello dears !!!
Earn on the orders of snow maidens for the new year ! And spend the new year with one of them...!!!!)))
Снегурочка к Новому году!!!))) 2019 ! Заработать тут >>>
Приветствую Вас! Наша команда фрилансеров предлагает широкий спектр веб-услуг по приемлимым ценам.
Создание под ключ сайтов любой сложности (блоги, журналы, порталы, сми, корпоративные, бизнес, визитки, портфолио, лендинги, интернет-магазины и т.п.)
- Аутсорсинг сайтов (поддержка сайта, работа с хостингом, админкой и контентом).
раскрутка:
- SEO пр0движение сайта в поисковых системах (внутренняя оптимизация + внешняя) по ключевым запросам в топы.
- SMM продвижение сообществ и аккаунтов в любых соцсетях (комплексные методы).
- Ведение аккаунтов в соцсетях
- Настройка и запуск таргетинговой рекламы (Вконтакте, Одноклассники или Фейсбук).
- Копирайтинг нового контента для сайтов и соцсетей.
- Настройка и запуск контекстной рекламы (Яндекс Директ или Гугл Эдвордс).
Почтовые рассылки:
- E-Mail рассылки (почтовый маркетинг).
- Прогоны по форумам и контактным формам.
- Сбор баз для рассылки
- Продажа готовых баз для рассылки на разные тематики.
- Рассылки по бесплатным доскам объявлений
Веб-дизайн для сайтов и групп в соцсетях
- логотипы, баннеры, визитки, флаеры и обложки;
Хотите попробовать и начать сотрудничать? Созвонитесь со мной. На первый заказ веб-услуг для Вас действует скидка до 10%!
Портфолио: в поиске ищите как "веб лейбл"
Профиль: https://freelance.ru/weblabel / https://www.fl.ru/users/weblabel/
ВК: https://vk.com/weblabel_ru
Контакты:
e-mail: weblabel @ bk . ru (убрать пробелы)
Скайп: weblabel
В поиске: веблейбл
Код для скидки: 148810202
Непревзойденное покрой, надежность, эффективность и долголетие компактной спецтехники Bobcat обуславливают стремительный умножение ее популярности во всем мире, что в свою очередь благоприятно сказывается для уровне продаж. Не стала исключением в этом плане и Россия, некоторые регионы которой известны сложным ландшафтом и суровым климатом. В таких малопригодных чтобы работы условиях техника Bobcat точно нельзя лучше демонстрирует принадлежащий потенциал, способствуя повышению количества проданных моделей.
Более подробно о Bobcat:
Колесные погрузчики
Номинальная грузоподъемность:
Min-343кг Max-1758кг
Гусеничные погрузчики
Номинальная грузоподъемность:
Min-505кг Max-1611кг
Экскаваторы
Рабочая масса с навесом:
Min-1138кг Max-5570кг
Телескопические погрузчики
Номинальная грузоподъемность:
Min-2200кг Max-5000кг
Бобкет