Pull to refresh

Comments 120

Нахуя это? Что за блять мода пошла тянуть всякое говно в PHP. Зачем усложнять себе жизнь?
Это мощный и удобный инструмент. Данный порождающий шаблон очень удобен, если в приложении используется большое число интерфейсов и зависимостей.
Почему бы не использовать его в PHP?
Приведите пример, я абстракциям не верю.
Пример — Symfony2 фреймворк. В JAVA это Spring
Ок, только для полной аналогии напишите свою PHPVM или хотя бы сделайте JPHP :)
Действительно, полная аналогия!
Вы наверное не совсем понимаете задачи JVM.
А sandbox нужен только если вы даете левым людям на сайте гонять команды PHP.
sandbox нужен что бы запускать там свои проекты. по крайней мере мы так его используем. Стоит заметить что у нас проекты являются php демонами.
Обратите внимание на flow3.typo3.org/ и DDD.

Как пример, зачем может быть нужен dependency injection:
— У вас есть два контролера в которых для обработки запроса нужно выполнить некоторые действия с объектом account
— Для объекта account имеется объект AccountRepository который умеет по разному искать acount ( по id, по имени,… )

Как вы получите ссылку на объект AccountRepository в контроллерах? В случае с DI Вам ни о чем беспокоиться не надо — ссылка будет вставлена в контролеры автоматически.

Посмотрите, во тут есть больше информации по этой теме: flow3.typo3.org/

Если в приложении используется большое число интерфейсов и зависимостей, то ваше приложение на PHP будет очень медленно работать.
Любители извращений незабудьте еще в карму насрать, у меня она резиновая.
Ладно уж, вернул в зад. Ну не стоит быть настолько категоричным!
Нельзя быть таким мягким.
да жалко беднягу… Быть может еще одумается =)
У меня на проекте очень часто проходится работать со сторонними сервисами. Например, в качестве CDN мы используем Amazon CloudFront, для рассылок mailchimp, для e-commerce Cleverbridge. А еще существуют разные CRM, с которыми тоже нужна интеграция. Так вот, при помощи DI, если правильно выделять абстракции, можно заменить любое звено в цепи. А если вы пишете тесты для своего кода, без DI вообще трудно обойтись.
а можно целостный, приближенный к реалиям пример?
IoC выстреливает на крупных проектах, идя рука об руку с TDD и другими enterprise прелестями. На простых примерах показывать это бесполезно.
в языке с явной типизацией использование этого патерна оправдано, за счет того, что в случаи изменения не нужно править везде типы. Здесь же я боюсь, что это скорее замедлит выполнение скрипта, нежили облегчит разработку. Вы проводили бенчмарки?
Причем тут вообще типизация? Менять типы при рефакторинге все равно придется, и IoC тут не поможет.

Разговаривать же о бенчмарках, обсуждая паттерн, который повлияет на всю архитектуру приложения, мягко скажем, некорректно. В данном случае намного важнее понимать чем и за что платишь. Похожая же ситуация и с XSLT, например.
согл: все что замедляет работу скрипта нах…
из-за этого мы отказались от Фемты.
Купи новый сервер для скриптов, пиши намного более читабельный код, а не чуть быстрее работающий.
мой код и так читабельный
ни кто не жалуется.
UFO just landed and posted this here
В статье я привёл простой пример. Думаю его должно быть достаточно что бы понят зачем использовать IoC. (Попробуйте инициализировать объект Manager без IoC)
Я, наверно, не понимаю чего-то важного, но без этих штук объект Manager, имхо, инициализируется как
new Manager(new Foo(), new Boo(), new Woo())
В чём преимущество-то? В том, что при создании менеджера нам хочется не знать, какие реализации используются? Так всё равно есть кусок кода с вызовами register(), в котором это придётся знать…
Нет, неправильно. Вот правильный вариант:

new Manager(new Foo(), new Boo(new Foo()), new Woo(new Foo(), new Boo(new Foo())))

И классов может быть ещё больше. Данная библиотека успешно используется в дном проекте с огромным количество классов и значительно облегчает их генерацию.
И проблема в другом, например у вас есть иерархия классов, и как нижнем уровне вам нужен объект Foo, тогда вам придется передавать объект через все вышестоящие уровни.

Естественно вы можете использовать pull подход и получить нужный объект прямо в конструкторе, но при использовании push подхода, IoC контейнеры облегчают жизнь.
Объяснить-то легко. Проблема в обосновании почему это вообще может быть полезно. Лично я не могу себе представить простого примера, где бы у вдумчивого читателя не возникло мысли «а нафига на это тратить свое время?»

А разговаривать о больших командах, низкой связанности кода, простоте тестирования и т.д. лично я простым языком не умею:(
UFO just landed and posted this here
Я чуть-чуть о другом. Кроме плюсов всегда есть и минусы. И не всегда бывает просто объяснить почему и когда плюсы плюсов больше.

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

Можно сказать о простоте тестирования и более низкой связанности кода. Но… Многих ли это убедит? Хотя, возможно, это просто я плохо умею выражать свои мысли.
UFO just landed and posted this here
Вобщем-то выглядит круто но непонятно для чего это надо.

Я уверен что все паттерны были придуманы во время решения какой-то конкретной задачи для которой этот паттерн лучше всего подходил. Причем паттерном я в данном случае называю не только какие-то идеи реализации а и конкретные «фичи» языка.
Например если вам нужно реализовать «принятие решения в зависимости от входных параметров» вам подходит паттерн «if-then-else».
Я сейчас очень упростил идею «паттернов», но и в классическом их понимании всегда подразумевается конкретное применение.
Например для синглтона есть отличный пример — драйвер работы с базой данных. Его всегда приводят в пример и всем сразу становится понятна суть.
Некоторые паттерны даже получили название в честь этого самого примера, как например «реестр».
Это я все к чему: Сколько не читаю про DI, все примеры откуда-то из космоса взяты.
Есть какой-нибудь хрестоматийный пример, а?
Хрестоматийный пример:

У вас есть большой проект. В нем много классов моделей, которые мапятся на таблицы в базе данных. Раньше вы использовали синглтон для драйвера работы с базой данных и были счастливы. Но с увеличением нагрузки пришлось выполнить шардинг вашей базы данных. После шардинга из одной базы данных стало две. Теперь нужно два инстанса драйвера базы данных с различными настройками подключения. При этом в зависимости от модели должен возвращатся правильный инстанс базы данных. Понятное дело что синглтоном уже не обойтись. Вот тут и приходит на помощь паттерн DI.

Как это все выглядит?

Создается класс, например, DIManager. У этого класса есть метод getDbConnection( $modelName ), который в зависимости от имени модели возвращает инстанс соответствующей базы данных. Теперь все старые вызовы DBConnection::getInstance() заменяются на DIManager::getDbConnection( $modelName ). Таким образом мы ослабили зависимость модели от базы данных и теперь спокойно можем контролировать коннекшн к бд для любой модели в одном месте. Профит!

П.С.: Хрестоматийный пример IoC на PHP пока не придумал, но ворох интерфейсов и набор магических заклинаний мне кажутся избыточными и монструозными.

П.С.С.: Нельзя использовать паттерны только ради того что бы они были. Это ошибки неопытных программистов.
Странный у вас шардинг, конечно… По имени модели работает.
Да и вообще-то синглтона в вашем примере более чем достаточно.
При необходимости осуществить конекшн на другой шард — создаем новый конекшн.
А его уже вызываем из синглтонов. Впринципе вряд ли у вас один скрипт будет последовательно писать на много шардов, а значит такой подход как раз пойдет.

Короче, променяли KISS на Keep it Enterprise
UFO just landed and posted this here
Кстати, какие тогда вообще конкурентные преимущества в РНР? Если я усвою все эти паттерны и они мне понравятся, я просто уйду кодить на Джаве. Там платят больше. А принципы те же, только лучше.
Вот кстати, я думал на Джаве кодить, а за последние полтора года зарплаты в PHP для толковых разработчиков стремительно догоняют зарплаты программистов на Джаве. Передумал в общем пока что, потому что там с джуниора начинать опять уже не особо есть желание.
Но за полгода вы можете там достигнуть такого уровня зарплат, которых в РНР вы никогда и не увидите. По крайней мере, я слышал много таких success story. Люди меняли профиль, или просто устраивались на новое место джуниором, а потом быстро становились senior'ами и выше.
UFO just landed and posted this here
Возможно, не спорю.
На самом деле, без разницы, на PHP или на Java, всё равно предел есть, который уже только карьерным ростом можно преодолеть, а не профессиональным.
В транс-национальном аутсорсере карьерный рост намного вероятнее, чем в стартапе или интернет-магазине.
UFO just landed and posted this here
Причем тут паттерны. Вы представляете себе объем информации по J2EE?
Чтобы выйти на Senior Java Developer нужно как минимум знать: persistence, spring, servlets, ejb, maven,… иметь опыт с каким-нибудь application server и тд…
с архитектурой шардинга ты что-то немного напутал. Мой шардинг имеет одно подключение к БД. Номер Подключения определяется еще на этапе инициализации Приложения в зависимости от входных параметров. Как-то так должно быть. Или на худой случай используем прокси соединение.

Если у тебя 10 серверов БД — что будем держать соединений — бред сивой кобылы. А 40 серверов?
Это не случай из жизни, просто хотел на скорую руку привести пример DI.
Если у вас есть пример DI лучше то милости просим, мы его с удовольствием обсудим.
у мня нет примера из жизни ДИ, просто у меня есть опыт разработки Hi-проектов, в том числе организации шардинга.
все старые вызовы DBConnection::getInstance() заменяются на DIManager::getDbConnection( $modelName )

И что изменилось? Была статическая зависимость на DBConnection, стала на DIManager. При этом DIManager к внедрению зависимостей имеет отношение только двумя буквами в названии.

Для решения задачи используется либо регистр, который делается синглтоном, либо более продвинутая реализация — сервис локатор.
Скорее всего вы правы, это именно сервис локатор. Немного не удачный я выбрал пример что бы объяснить DI
Паттерны не зависят от языка.
Я не против, я лишь слегка расширил концепцию.
Например трейты в пхп 5.4 я тоже считаю паттерном.
DI — очень гибкий паттерн. Вы, возможно, удивитесь, но он может заменять даже синглтоны (которые в «чистом» виде являются злом в большинстве случаев, например — в вашем применении к работе с БД). Как-то так это может выглядеть:

$di->addService('MyDbConnection', '\My\Super\MySqlConnector');
$di->addClass('ClassThatUsedDb', '\My\Super\Class', array('&MyDbConnection')); // 3й аргумент - массив параметров конструктора
// ...
$di->newInstance('ClassThatUsedDb')->makeWorkWithDb();


Теперь рассмотрим такой пример. Допустим, вы приняли стратегическое решение перейти с MySQL на Postgre. Что надо сделать в случае простого синглтона? Написать новый класс-синглтон, найти все вхождения в коде, включая все классы, использующие его (которых может накопиться ой как много), и переправить все на новый класс. Что надо сделать в нашем примере? Заменить одну строку:

$di->addService('MyDbConnection', '\My\Super\PostgreConnector');


(естественно, предполагается, что интерфейсы классов MySqlConnector и PostgreConnector совпадают).
Если интерфейсы классов совпадают мне не нужен никакой DI.

В этом случае мне гораздо проще использовать Adapter как это сделано в Zend_Db
Если уж говорить о паттернах, то, в Zend_Db используется «абстрактная фабрика», если я правильно понимаю. Паттерн «адаптер» как раз организует совместную работу классов с несовместимыми интерфейсами.

Ну а DI может заменить вам и абстрактную фабрику, если уж на то пошло. Говорю же, гибкий паттерн :) Однако я не настаиваю на его использовании везде и повсеместно.
Ну так он этим и занимается. Есть например mysql_*() и pg_*()
Ну да, ето не классы а наборы функций, но ето не суть. Вот он (адаптер) и организовывает их работу в один интерфейс.
Абстрактная фабрика там хоть и используется но решает другие задачи а не ту которую вы описали (проблема переключения между двумя базами данных).

Паттерн конечно гибкий я это уже заметил, применить можно где-угодно. Но это не то что я интересно.
Хрестоматийный пример это когда без паттерна пришлось бы его (паттерн) изобрести.
А тут какой пример ни приведут все время есть варианты с более узкоспециализироваными решениями которые очевидней или просто «понятней» синтаксисом.
Вопщем требую адекватных примеров! :)
Ну так он этим и занимается. Есть например mysql_*() и pg_*()

Опять же не совсем точно, там используется PDO, которое уже обеспечивает абстракцию от конкретных функций конкретной БД. Но это, не суть, я понял, что вы имеете ввиду. В моем изначальном примере MySqlConnector и PostgreConnector тоже могут быть адаптерами.

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

а) делает код менее связанным, за счет того, что классы не создают внутри себя экземпляры других классов, а хранят тока ссылки на объекты нужных классов, которые поставляет им контейнер;
б) дает возможность собрать всю информацию о связях между классами в одном месте, где удобно впоследствии будет вносить изменения, причем, это зачастую можно сделать декларативным способом (как пример — в симфони можно использовать для описания YAML или XML);
в) нужные классы-сервисы инстанцируются только когда нужны, и автоматически инстанцируются все связанные классы. Например: где-то вначале своего кода вам захотелось сконфигурировать работу БД, вы пишете что-то вроде этого:
$db = Zend_Db::factory($this->_config->db);
// Задание адаптера по умолчанию для наследников класса Zend_Db_Table_Abstract 
Zend_Db_Table_Abstract::setDefaultAdapter($db); 

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

Разумеется, не следует пихать в контейнер абсолютно все классы вашего проекта. Лично я придерживаюсь такого подхода: классы из одного пространства имен знают друг о друге и используют друг друга напрямую, а в DI описываются только некие классы-сервисы (вроде того же подключения к БД, или какого-нибудь Mail'ера и т.п.), которые широко используются в разных частях проекта.
Все это круто, конечно же, но DI уместен скорее при разработке универсального фреймворка нежели частного проекта. Почему? Потому что при разработке частного проекта вы знаете и уверены в том что вам нужно для разработки, и по этому у вас не встанет вопрос перехода с одной СУБД на другую. По этому в частном проекте вы будете тратить время на реализацию реальных задач, а не на нагромождение абстракций с целью обезопасить себя на тысячу лет вперед от всех возможных случаев жизни.

С другой стороны, если вы разрабатываете открытый фрейморк, которым будут пользоваться не только вы и ваша команда (аля symfony, zf, ci, yii, etc), то вы не будете уверены в том что именно захочет сделать пользователь вашего фремворка. И тут вам придется городить огород из махровых абстракций, что бы угодить всем и вся.
Абсолютно согласен. Я и не агитирую за использование DI в частных проектах, просто попытался прояснить человеку, какие можно получить выгоды от использования.
Оо, вот это уже что-то. Если честно, для меня сейчас совершили открытие тем фактом что пользы от DI в частных проектах мало.

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

Мне кажется что в статьях про DI это надо писать в первых абзацах. Что то типа раздела «Цели и решаемые задачи».
Все зависит от того, что у вас за частные проекты :)

Быть может, вам не нужно будет самому реализовывать этот паттерн, но можно получить выгоду от использования готового решения, например в том же Сифони
Случай, когда меняется класс, но не меняется инерфейс не так уж сложен. Сложен он когда меняется интерфейс и тут уже ни DI, ни IoC, ни что иное не помогут.
Тут может помочь только модель событий, с помощью которой можно будет подменять данные, при вызове устаревшего класса. Но это возможно только в сучае изначального внедрения такой модели в проект.
Например, у меня используется система, при которой на одно и тоже событие могут отреагировать несколько классов и решение о том какой именно отреагирует система принимает в зависимости от состояния.
А что по поводу этой библиотеки от Sensio которая используется в Symfony2
ета версия библиотеки подходит также и к php 5.2, котого еще ох как много где
Как то дурно это все пахнет. Какой то неявный Registry, что наводит на мысли что магия это зло, если это не возможность языка. Это как с аннотациями, когда начинают парсить аннотации с комментариев в скриптах, блевать хочется.
Ну если есть хорошее описание аннотаций, которые будут парситься, то все очень даже удобно. Doctrine тому пример.
DI — может быть очень полезна для сложных проектов и лечь в архитектуру проекта. Но тут, как говорится, главное не переборщить.
>> то все очень даже удобно
Это ваше субъективное мнение. Не только я лично отказываюсь от этой ОRМ в частности из-за этого. Считаю полнейшим бредом добавлять возможности на основе комментариев (строк) в язык. Если это считать как ничего страшного то можно дойти до того что будут реализовывать декораторы в манере python только с помощью строк.
Насчет DI тут кому как нравиться, у меня руки не отвалятся написать явный реестр явно инициализированных объектов, а не городить обертку ради очень сомнительной выгоды в динамическом языке. Вы можете ссылать на какой то абстрактный «большой» проект, но лучше если бы вы реально написали какой плюс от DI на реальном примере.
>> явный реестр явно инициализированных объектов
Вот это место и является минусом из-за инициализации на каждом запросе всех нужных и ненужных объектов.
В DI это решается контейнером с лямбда функциями.
Другое дело, что вместо DI можно обойтись ServiceLocator, но тут уж как кому удобно.
Так можно как понадобится инициализировать, а не сразу.
Я использую Lazy initialization, Proxy, Registry, причем от третьего иногда отказываюсь. DI я использовал и у меня появлялись постоянно преграды в рефакторинге, а когда нужно быстро сделать прототип проекта это занимает очень много время в Lazy initialization или Proxy мне приходится переписать всего один метод в случае изменений и поверьте с головой хватает, причем все вещи сделаны явно и производительность не страдает совсем(!).
P.S. Замыкания по сути тоже инициализация, только объекта класса Closure. Безусловно неким количеством памяти можно пожертвовать на это но зачем? Я просто выгоды не вижу. Да получается статика, но явная статика ты полностью уверен что метод возвращает нужный тип/класс.
А вообще задача решает все. Но ИМХО в 98% DI в PHP вообще не нужен и постоянно брать его за основу для «больших» проектов можно только по очень большой приверженности к нему.
Остальные 2 процента — это тестирование. Потому что в реальной практике я могу вспомнить пару примеров, когда подмена нужна была, но оверпрограмминг с использованием DI больше чем все эти случаи вместе взятые. Хотя я и использую вариацию на тему — сервис локатор, при этом он задевает малюсенькую долю инстанцирования.
А это как раз возможность языка: ReflectionClass.
Service Locator (или Registry) работают по pull принципу, т.е. классы сами вытягивают зависимости и имеют статическую зависимость от, собственно, Service Locator. В случае IoC контейнера внедрение происходит по push принципу, т.е. с точки зрения классов инъекция происходит через конструктор / сеттер.

Профит:
— отсутствие статической зависимости;
— упрощение модульных тестов.
Магия только в примесях. Все понравилось. Тем, кто ничего не понял читать в таком порядке:
Устранение зависимостей в коде.
Паттерн фабричного метода.
Идеалогия интересного программирования.
Книга: чистый код.
Както так.
Теперь пример: вы делаете фабрику машин, и подшипники вам поставляет Бош, а втулки Сименс (реализация интерфейса) и теперь вам не нужно обучать ваши агрегаты работать с этими деталями.
интересный пример, нельзя ли поподробнее?
то есть с помощью этой магии втулки от Сименс в любом случае подойдут к подшипникам Бош?
Если бы Сименс делали втулки на PHP они бы разорились минуты через две после начала выпуска 0.о
ага, теперь я понял, нам не нужно обучать наши агрегаты работать с этими деталями, так как в агрегатах не используется PHP, чорд, так и думал!!! спасибо ;)
Смайл. Вы решили проблему, но ваше решение и породило эту же проблему. теперь у вас нет возможности подменить ioc. Нужно избавляться от Singleton и такскать инстанс, например, инъекцией в конструктор.
p.s. Сам пользуюсь смешанным подходам, но идеологически верно без него.
Идеологически верное решение породит довольно неудобный для повседневного использования синтаксис.
В этом и печалька, не всё правильное является удобным.
Вот вы в Yii используете много статики и это удобно в сравнении с правильным Zend Framework, где для любого чиха нужно не менее десятка классов, затем ещё настроить длиннющую цепочку вызовов. А в итоге получается уродец Zend_Db_Table, недавно писал модуль учёта финансов с использованием подхода из quickstart, очень советую попробовать, а лог профайлера бд лучше не включать.
У нас статики, кстати, не так много: DI-подобный контейнер Yii::app(), фабрики моделей CActiveRecord::model(), ну и остальное совсем по-мелочи.
ну есть же такая вещь как autowiring. ну и имплементация его на PHP совсем не одна. и синтаксис в таком случае доооовольно удобен. так что не надо ето…
Удобнее, конечно, чем голый DI. Тут не поспоришь.
А вы не смотрели ли на Pimple? Всего то 149 строчек кода и практически весь функционал DI есть. Все просто.

Если же кому нужно множество примеров с применением DI/IoC именно в PHP — тогда, пожалуйста, вам сюда.
Отличная презентация, очень всё понятно и аргументировано. Есть ещё что посмотреть в таком же качестве?
Можете пояснить, почему на 62-м слайде сказано, что при

        $container->user = function($c){
                static $user;
                if(is_null($user)) {
                        $user=new User($c->storage);
                }
                return $user;
        };


истинным является подобное выражение:

spl_object_hash($container->user)!==spl_object_hash($container->user)


У меня наоборот, хеши объектов равны, да и из кода это очевидно. В чем я ошибаюсь?

Насколько я понял, это до реализации 63-го слайда объясняется ситуация. После реализации они равны и это видно дальше на слайде 64.
Хм. Понятно. Несколько неоднозначно.
Вкратце выскажу мнение. Скорее всего DI в том виде в котором его подают не нужен для большинства задач.
Он нужен для разработчиков библиотек, продуктов и пр. Для веб-сайта и веб-приложения как раз не столь необходим.

Суть Dependency Injection ясна и правильна, но вот контейнеры это зло. Потому что если вдруг оказалось, что какой-то класс мы забыли добавить в контейнер, то нужно рефакторить весь код и заменять все вызовы. А зачастую так же все и происходит. Сначала у вас класс простой, а потом он разрастается, появляются зависимости, их нужно конфигурить… И в момент, когда вы понимаете, что вам нужен DI для этого класса, необходимо рефакторить код. Короче, какая-то дедукция в разработке получается.

А ещё зло эти ваши фабричные методы. Никогда не знаешь что оно вернет и с какими методами/свойствами. То как реализованы в доктрине вызовы репозиториев, это вообще печаль — никогда не знаешь какие методы в этом репозитории. Каждый раз нужно отдельно открывать файл репозитория и проверять сигнатуры нужных функций.
необходимо рефакторить код
Код необходимо рефакторить всегда, до этого момента, после этого момента, вместо этого момента и даже вместе с этим моментом :)
Ага, не решать конкретные задачи, а рефакторить код. Господа, так не бывает.
Есть бизнес-задачи, есть рефакторинг. Бизнес-задачи приоритетнее. ТОт паттерн эффективнее, что помогает избегать рефакторинга, а не тот, что провоцирует его. Иначе вообще зачем нужны паттерны, если в случае чего мы будем перестраивать архитектуру?
Если для решения конкретной задачи требуется изменить 5 классов и наговнокодить, а задачу нужно решить прямо сейчас, то обычно говнокодят и ни завтра, ни послезавтра никто не рефакторит. А потом еще наговнокодят и опять не рефакторят. Поэтому, я считаю, нужно рефакторить сразу, независимо от того, насколько срочная задача. Появление бизнес-задач, которые нужно решить прямо сейчас — ошибка менеджмента, планирования, etc.
Рефакторинг — это часть любой бизнес задачи. Не бывает кода, который когда-то не придётся изменить в связи с новой бизнес-задачей, как и не бывает кода без багов. Можно ведь и баги не исправлять, если новые бизнес-задачи приоритетнее.
Без рефакторинга любая бизнес-задача с каждым днём будет отнимать всё больше времени. Процесс разработки любого продукта и новых фич должен включать в себя рефакторинг.
А ещё, для эффективного, быстрого и качественного рефакторинга нужно писать тесты, писать тесты!!!, ПИСАТЬ ТЕСТЫ БЛЕАТЬ!!!111 :)
Ок, но какая основная мысль?
Мы можем начать писать сайт как <?php echo "Our Site" ?>
а потом при усложнении бизнес-задач его рефакторить?

Наверняка нет. Если вы рефакторите — значит нынешняя архитектура недостаточно продумана или просто устарела для решения текущих задач. Если есть возможность создать расширяемую архитектуру, и нововеденья внедрять в неё без гавнокода, значит не нужно рефакторить после каждого чиха.

Архитектура тем лучше чем меньше в ней надо будет рефакторинга.
Ну а я привожу пример того, что DIC в этом плане недостаточно хорош.
Рефакторинг всё равно будет, независимо от того, как продумать архитектуру.
Даже отличный архитектор ПО никогда не может всего предусмотреть.

А вообще, тут немного разные подходы к разработке обсуждаем просто. Я с уклоном в Agile, а у вас больше про полный жизненный цикл с серьезным подходом именно к проектированию приложения. И то, и другое, имеет право на жизнь, только во втором случае обычно есть четко формализованное ТЗ, которое всё равно уточняется в процессе проектирования, а в первом обычно нечего проектировать, так как требования к продукту меняются быстрее, чем их реализовывают.
Будет. Но разница только в том сколько времени на него тратится. Если это время можно сократить (не в ущерб качеству кода), значит больше времени остается на решение бизнес-задач.

Рефакторинг — это изменение реализации, без изменения внешнего поведения. Т.ч. рефакторинг по определению не может изменять архитектуру :)
0.o

Как отношение имеет архитекутура к внешнему поведению?
Архитектура — набор компонентов системы и взаимодействие между ними. Рефакторинг компонента не затрагивает его поведение, а меняет только реализацию.
Есть внешний API и внутренняя реализация.
Архитектура это обычно как раз построение реализации.
При чем здесь API? Графическим представлением архитектуры системы будет UML модель, на которой отражены компоненты, классы и взаимодействие между ними. О конкретной реализации классов архитектура ничего не говорит.

В первом комментарии я немного погорячился. Точнее будет сказать, что рефакторинг существенно не влияет на архитектуру. Он модифицирует реализацию классов / компонентов, обычно незначительно затрагивая интерфейс.
Ок, но какая основная мысль?
Мы можем начать писать сайт как <?php echo «Our Site» ?>
а потом при усложнении бизнес-задач его рефакторить?


Про это не сказал. Если сегодня задача стоит вывести на странице «Our Site», то я так и сделаю, как в примере. А завтра будет новая задача — естественно рефакторить.
После появления новой задачи ты будешь просто программировать :)
Всё верно, такой подход оправдан в сложных, модульных приложениях, где требуются точечные изменения кода, но без возможности непосредственной правки классов. Контейнер позволит просто подменить экземпляр на свой класс, с сохранением интерфейса.
Если фабричный метод возвращает интерфейс, то никаких проблем нет. Клиенту не нужно знать о реализации. Это один из основных принципом ООП: инкапсулирование.
Не то что никаких… Скорее, их чуть меньше. В примере с репозиториями доктрины, ок, интерфейс есть. От этого легче? Нет. Всё равно сигнатура кастомных функций неизвестна. И вперед бегать по всем файлам, открывать тот самый репозиторий, смотреть его функцию… В интерфейсе может быть вообще одна функция, а в реализации их десть-двадцать. И потому интерфейсы не особо помогают :(
Работа в доктрине с ренозиториями не лучший пример. Мне самому это не нравится.
Но думаю вы не будете отрицать, что абстрауная фабрика это один из действительно полезных порождающих паттеров.
Фабричный метод и абстрактная фабрика — это как бы разные шаблоны.
Этот принцип называется полиморфизм ;)
Скрытие реализации — это инкапсулирование.
При чем здесь скрытие реализации и фрабричный метод?

Для того чтобы система оставалась независимой от различных типов объектов паттерн Factory Method использует механизм полиморфизма — классы всех конечных типов наследуют от одного абстрактного базового класса, предназначенного для полиморфного использования. В этом базовом классе определяется единый интерфейс, через который пользователь будет оперировать объектами конечных типов.
Описывая интерфейс, вы скрываете реализацию (инкапсулирование). Затем для генерации экземпляров вы используете фабричный метод (полиморфизм).
Sign up to leave a comment.

Articles