Мы все живем в современном, быстро растущем и меняющемся мире. Новые современные технологии и методики разработки появляются с ужасающей скоростью. Не успеешь закончить какой то проект, как смотришь, уже появились решения, с помощью которых можно было все сделать проще и быстрее.
Сложность больших проектов в их неспособности быстро адаптироваться под все новое и современное. А надо ли? Этот вопрос всегда вызывает много споров и разногласий. В конечном итоге все сводится к тому, что особо не надо, но все равно приходится. Программист который отлично писал на PHP4, но забил на изучение PHP5, может сегодня остаться без работы. Хотя в проектах, которые он делал, фичи PHP5 по большому счету не нужны. Проект и так хорошо работал (и возможно работает) на PHP4.
Сейчас паттерны проектирования(design patterns) считаются хорошей практикой разработки. Это практика стала настолько хороша, что иногда программисты вставляют паттерны везде где только можно, не задумываясь, а нужны ли они тут вообще. Современный разработчик как правило знает несколько распространенных в практике паттернов (обычно это singleton, factory method, observer, decorator, возможно MVC).
На практике не всегда можно сходу "узнать" паттерн в коде приложения, т.к сам паттерн описывает некую архитектурную конструкцию приложения, но не ее реализацию в коде. Итак, хочу познакомить вас с несколькими паттернами проектирования, реализованными в битрикс
Небольшое отступление: вообще тема про паттерны в битрикс возникла случайно в моем разговоре с Александром Сербулом. Он хотел написать про это, но похоже я его немного опередил. Возможно ему будет что добавить от себя.
Observer(наблюдатель)
Мы все очень часто пользуемся обработчиками событий в битрикс, вещаем их на инфоблоки и другие объекты, так вот это очень похоже на observer. Классический observer немного более ограничен, т.к не имеет информации о том, какое событие произошло. Другой кандидат на эту должность это event dispatcher.
Singleton(одиночка)
В точности singleton в битрикс не реализован, но можно предположить, что глобальные переменные $APPLICATION и $DB это как раз прямые кандидаты в singleton.
MVC (Модель - представление - контроллер)
Мы все про него много знаем . Всем нам вдалбливали в голову, что при разработке web-приложений нужно обязательно следовать MVC. Да, я согласен . MVC в битрикс - это компоненты 2.0. Компонент - это контроллер, шаблон - представление, а модули - это модель.
Front controller (единая точка входа в приложение)
Это мой любимый паттерн . В битрикс его нет, но если предположить, что есть некий глобальный комплексный компонент для всего сайта, то его можно будет назвать Front controller.
Adapter
$DB это практически и есть адаптер. Мы подключаем конкретную реализацию для конкретной базы данных, при это все реализации имеют единый интерфейс для работы с базой.
Decorator
Компоненты 2.0 кроме MVC это еще и немножко декораторы. Мы можем изменить поведение компонента вне самого компонента, например в эпилоге компонента. Правда decorator предусматривает наличие двух объектов, а у нас компонент и эпилог объектами не является, но общее с decorator все равно есть.
Стоит добавить, что в битрикс не совсем очевидная реализация вышеперечисленных паттернов. Возможно некоторые другие паттерны я упустил из виду. Кстати компоненты 2.0, если верить мануалу битрикс, реализуют другой паттерн - Carrier Rider Mapper. Я сути этого паттерна не уловил, поэтому для меня это просто MVC.
Суть в том что там есть часто повторяющиеся участки кода, коотрые не в классы, а хотя бы в функции можно было вынести). Разбирать этот компонент новичкам было бы намного проще. Да и занял бы он меньше строк
Вот абстрактная ситуация. За основу можно взять не компонент заказа а любой другой. Представим, что у нас компоненты это классы).
Существует 3 компонента. 1 Компонент базовый, реализующий базовую логику. Остальные 2 - это компоненты наследники, которые наследуют логику базового компонента. Теперь если нужно внести изменения в базовую логику, то нужно внести только 1 правку в код базового компонента, а не в 3 отдельных).
Вероятность ошибок уменьшается и код становится более понятным.
Можно использовать при разработке классы и при этом все равно писать код основанный на функциях:). Суть не в том чтобы использовать классы при написании программы типа "hello world". А в своевременности и правильности их использования.
Более точно говоря, один класс . Наши компоненты, которые мы пишем, классами не являются, это просто внедряемый кусок кода в пространство имен метода класса.
почти поржал . а теперь попробуйте внести в эти классы изменения и чтобы они при этом не затерлись обновлениями). Ну и кроме того это классы которые реализуют не логику работы конкретного компонента типа news.list, а реализуют только интерфейс работы с компонентами в целом.
Я так понимаю, по поводу полиморфизма возражений нет? Мол, мы тут в базовом классе логику поправим, и она волшебным образом унаследуется в дочерние классы?
И вам же вопрос, цитирую: "Я так понимаю, по поводу полиморфизма возражений нет? Мол, мы тут в базовом классе логику поправим, и она волшебным образом унаследуется в дочерние классы?"
Дмитрий а зачем вам в конкретном данном случае полиморфизм. не секрет, что классы наследники наследуют логику базового класса:). И достаточно внести изменения в логику работы базового класса, чтобы она "появилась" в дочерних.
Я думаю что чем проще тем лучше. В данной конкретной задаче. По которой я привел конкретный пример, по моему полиморфизм не нужен, но если он понадобится, то можно будет им воспользоваться, переопределив соответсвующие методы в классах потомках.
Я имел ввиду что логика которая сейчас пишется в компонентах. должна быть оформлена не в виде строк кода а в виде класссов. Может я не так выразился в предыдущих постах
Я понял тему . ДА Дима, ты прав, если есть некий код в методе абстрактного класса, то для его модификации в потомке придется все равно его копипастить. Можно немного выкрутиться, часть кода перенеся в вспомогательные методы(типа helpers), но это будут те же костыли. С другой стороны, если изменения не глобальны, а затрагивают только пре/пост обработку, то вариант с наследованием пройдет, другое дело, что сейчас на нынешних компонентах можно сделать тоже самое через эпилог(как вариант).
Существует 3 компонента. 1 Компонент базовый, реализующий базовую логику. Остальные 2 - это компоненты наследники, которые наследуют логику базового компонента. Теперь если нужно внести изменения в базовую логику, то нужно внести только 1 правку в код базового компонента, а не в 3 отдельных).
Сдаётся мне, что если вы хотите внести изменения в базовую логику, вам придётся вносить изменения в ядро битрикса.
Если хотите оспорить, предложите схему, когда базовый класс не принадлежит ядру битрикса и доступен для изменений. Либо вам придётся взять процитированные выше слова обратно и предложить схему, когда базовый класс недоступен для изменений, а логику можно менять в дочерних классах, но тогда я не понимаю, чем эта схема так уж хороша.
Стоят на полочке все две книжки. 1. Хороша конечно, но PHPшникам без знаний каких-нибудь системных языков лучше туда не лезть. Очень трудным языком написана. Если хоть каких-то знаний в шаблонах нет, то с этой книжки начинать их изучение не стоит. 2. Самый оптимальный вариант. Так сказать адаптированный под PHP вариант первой книги -) Жаль, что примеры там не очень удачные, да и вообще код там не самый красивый, но сами паттерны описаны довольно понятно. Рекомендую.
должна быть оформлена не в виде строк кода а в виде класссов
ну почему? вот этого абсолютно не понимаю. особенно выражения ДОЛЖНО 1. ремонту и модернизации то легче поддается именно такое вот варево 2. по идее каждый компонент - он сам по себе и иногда излишняя "классификация" внутри одноклеточноо организма вредна 3. кто вообще сказал, что все должно быть классифицировано? Что за строгое стремление быть всегда правильным? И кто сказал что Битрикс должен быть СТРОГО ООП? В первую очередь он должен быть удобным в эксплуатации и обеспечивать максимальную скорость корректировки или разработки?
Carrier-Rider-Mapper - встречается не в компонентах 2.0, а в принципе "БД-API-клиентский код". Т.е. разработчик не пишет прямые запросы к базе данных (хотя физических ограничений этому нет), а использует нашу прослойку. Этот простой паттерн дает нам возможность менять схему БД и выпускать совместимые обновления. Хороший пример - Инфоблоки 2.0.
Т.е это больше медиатор, чем обсервер или конкретно при реализации событий придерживались именно этого паттерна? По типу использования событий, это все же сильно похоже на обсервер, т.к у нас только отношение объект инициатор -> слушатели события. Медиатор тут не совсем очевидно (имхо).
Смотрю КП и не понимаю.. почему одни объекты управляются из админки (элементы инофоблоков) тогда как другие только из публички (форумы, соцсети)? Почему для разных объектов (опрос, тема форума, группа соцсети) нельзя сделать какой-то единый интерфейс редактирования (форму), почему каждый раз колхозится что-то новое отдельное самостоятельное?
Ребята привет! Отличная полезная тема. От себя добавлю - в Битриксе не просто используются, а эффективно используется уже много лет несколько известных паттернов проектирования. Также, система не очень ООПшная, но это ей и не нужно - система довольно низкоуровневая, с простой и эффективной вертикально невысокой архитектурой, и предоставляет большие возможности разработчикам для комбинирования кубиков в своих паттернах для решения специфических бизнес-задач. Кроме того, многолетнее постоянное развитие продукта говорит о грамотно выбранной простой архитектуре - она гибка!
Рекомендую применять паттерны при интеграции, читать про них, но главное - не тулить "горбатого к стенке", а детально разобраться в каждом и понять, где он нужнен, а где нет - а для этого требуются годы сопровождения чужого "дурнопахнущего" кода
Сейчас я вам покажу базовый класс, детище так скажем нвого стиля программирования на платфоре: /bitrix/modules/iblock/lib/component/base.php
Это просто идеальный класс в качестве базового, он придерживается всех правил SOLID и контрактного программирвоания: вот краткиий список компенсаций этого класса
__construct
getAction
setAction
hasErrors
processErrors
setCacheUsage
isCacheDisabled
setExtendedMode
isExtendedMode
setCompatibleMode
isEnableCompatible
getSettingsScript
onPrepareComponentParams
checkModules
initCatalogDiscountCache
clearCatalogDiscountCache
initCurrencyConvert
offerIblockExist
initCatalogInfo
initPrices
initElementList
getIblockElements
sortElementList
makeElementLinks
getProductIds
getBigDataProductIds
getBestSellersRecommendation
getMostViewedRecommendation
getRandomRecommendation
filterByParams
getSectionIdByCode
getSectionIdByElement
filterIdBySection
getRecommendationLimit
getBigDataServiceRequestParams
getBestSellersProductIds
getBestSellersFilter
getDeferredProductIds
getProductIdMap
getProductsMap
getProductsSeparatedByIblock
getDefaultMeasure
getElementList
initQueryFields
getSelect
getFilter
getSort
initPricesQuery
parseCondition
parseConditionLevel
parseConditionName
parseConditionOperator
parseConditionValue
parsePropertyCondition
processElement
modifyElementCommonData
setElementPanelButtons
modifyDisplayProperties
getPropertyList
clearItems
loadMeasureRatios
getEmptyRatio
initItemsMeasure
getMeasureIds
loadMeasures
loadPrices
calculateItemPrices
transferItems
calculatePriceBlock
searchItemSelectedRatioId
compactItemRatios
getQuantityRangeHash
getFullQuantityRange
searchItemSelectedQuantityRangeHash
initUrlTemplates
modifyElementPrices
processProducts
processOffers
getIblockOffers
getOffersFilter
getOffersSort
modifyOffers
chooseOffer
initResultCache
getCacheKeys
processResultData
checkIblock
prepareData
filterPureOffers
makeOutputResult
processLinkAction
addProductToBasket
getRewriteFields
deferredLoadAction
bigDataLoadAction
initBigDataLastUsage
initialLoadAction
loadData
getAdditionalCacheId
getComponentCachePath
getTemplateEmptyPreview
sliceItemsForSlider - КОНЕЧНО ЖЕ ЭТО ДОЛЖНО БЫТЬ В БАЗОВОМ КЛАССЕ
getTemplateCurrencies
sendJsonAnswer
prepareAction
doAction
executeComponent
applyTemplateModifications
prepareTemplateParams
getTemplateDefaultParams
checkTemplateTheme
editTemplateData
checkEnlargedData
editTemplateProductSlider -КОНЕЧНО ЖЕ ЭТО ДОЛЖНО БЫТЬ В БАЗОВОМ КЛАССЕ
editTemplateOfferSlider - КОНЕЧНО ЖЕ ЭТО ДОЛЖНО БЫТЬ В БАЗОВОМ КЛАССЕ
editTemplateCatalogInfo
getTemplatePropCell
isNeedCheckQuantity
getUserGroups
getUserGroupsCacheId
initCompatibleFields
fillCompatibleRawPriceFields
getCompatibleFieldValue
checkQuantityRange
getEmptyPriceMatrix
Да, этой действительно прорыв.
А вот и контроллер подкатил, он как рах находится там где нужно:
Да лдадно, можно же контроллер езде сделать класс и везде одинаковые методы запилить
Ну и сладенькое обработка 404 страницы Должен быть обязательно тут Bitrix\Iblock\Component\Tools::process404 - это же к инфоблоам относится не иначе.
Один из принципов работы с классми на Java. Работа с данными класса (Data Class) производится этим же классом. И никакой класс не имеет права изменять данные другого класса. Это к вопросу о заказе, корзине в d7 там я могу поменять вообще 1 вещь а изменение пойдёт по цепочке. Я понимаю что нужно было сохранить консистентность заказа, он используя такой подход всё зарыли в методы и тем самым зарыли почти все способы влиять на это кроме опять тех же событий.
Продолжать можно безконечно. Я понимаю что сейчас тут все любители и защитники битрикса как обычно ополчаться и скажут вон отсюда. Я также понимаю что критиковать бесполезно. Что менять ничего никто не будет. Но я вас прошу не нужно говорить о паттернах, не соблюдая их от слова совсем. Если в коде пишется слово класс - это не означает что это ООП, от слова совсем, если кто-то придмал что компоненты это MVC - 'это не значит что это так.
По мне так ООП нет. Нарушены принципы open-closed, resopnsibility классов. И вообще отсутствует какая либо вменяемая стратегия развития всё как было хаосом так и осталось хаосом только в классах. Тот же бардачок только в ООП
Сербул Александр, У меня есть ряд предложений конкретно к коду и вообще к тому как повлиять на ситуацию в лучшую сторону. Но с кем я могу пообщаться? Потому что предложения мои довольно просты.
Микулич Евгений: Александр Сурбул за 6 лет уже мог сменить место работы, судя по дате публикации это статья 6-летней давности, поэтому интересно сейчас почитать ваш развернутый пример кода, в котором принципиально ничего не изменилось.
Группы на сайте создаются не только сотрудниками «1С-Битрикс», но и партнерами компании. Поэтому мнения участников групп могут не совпадать с позицией компании «1С-Битрикс».