| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > Java: Design, Quality, Testing > IoC: правила применения |
| Автор: Vitaly333 5.8.2011, 22:58 |
| Хочу отрефакторить ###код в своем проекте. Хочу использовать IoC - паттерн. Никогда его не применял, поэтому есть вопросы: В каких случаях требуется инжектировать зависимости а в каких нет? Если инжектировать все зависимости в каждом классе то тоже ничего хорошего не выйдет. Должна быть золотая середина. Есть какое-нибудь правило которым вы пользуетесь? Например, инжектируем только те зависимости которые могут быть изменены (подставлена другая реализация или мок) а те, для которых я точно знаю что они не изменятся я не трогаю. |
| Автор: Vitaly333 6.8.2011, 00:00 | ||||
Представляю какого размера будет конфигурационный-xml в том же Спринге, если у тебя >500 классов и почти каждый описан в нем.
А как можно его не использовать если ты хочешь писать инжектируемый код? И что это будет за "тупой" код? Фабрики ты имеешь ввиду? |
| Автор: Старовъръ 6.8.2011, 00:11 |
| Правильные вопросы задаешь, люблю когда люди сначала идут от теории Как правило следует инжектить все, что кнфигурируется. Например, у нас есть ДАО, который нужно передать в класс бизнес логики. Это пример зависимости, которую следует инжектить. Допустим в уровне сервисов мы трансформируем объекты одного класса в другой, причем конвертер никак не конфигурируется, его просто нужно создать и все. Это пример зависимости, которую нужно не ижектить, а создавать внутри самого класса. Правда затем нужно будет протестировать как-то этот сервис, что значит, что возможность инжектить все-таки должна быть, просто ее не следует использовать в production-коде (можно вместо этого использовать Отражение для установки мока на место поля). То есть в большинстве случаев инжектить следует только то, что конфигурируется на глобальном уровне. Иначе будет достаточно сложно как работать с контекстами, так и "бродить" по коду. Ну и объекты, которые нужны нескольким бинам, также логично помещать в контекст. |
| Автор: Stolzen 6.8.2011, 08:14 | ||
setXXX() И выделить отдельный класс-сборщик, который будет создавать, инжектить зависимости и отдавать клиенту интерфейс. Инжектить можно тогда, когда встает вопрос о соблюдении SRP (Single responsibility principle). Если класс начинает выполнять более одной работы, то желательно новую функциональность выделить в отдельный класс и делегировать выполнение этих операций новому классу (или интерфейсу + его реализацию инжектить). Плюсы - код чище, проще покрыть тестами (например мокнуть зависимость и заинжектить ее). |
| Автор: Старовъръ 6.8.2011, 10:06 | ||
Кстати, чтоб не было недопониманий: как Фабрики, так и IoC-контейнеры - это все Inversion of Control. Если хочется говорить конкретно об IoC-контейнерах, то лучше применять термин Dependency Injection (DI). ТС, почитай/посмотри про принципы объектно-ориентированного проектирования (OOD Principles), они смогут помочь когда станет вопрос "а как лучше":
|
| Автор: batigoal 7.8.2011, 13:30 | ||||||||||
Инклюды спасут отца русской демократии. Если твой код нормально бьется на модули, то будут раздельные конфиги на каждый модуль. Спринг в проектах на 500 классов - это, наоборот, большое подспорье, а не помеха.
Я имею в виду вот такие цепочки в классах, которые будут заниматься инициализацией всего этого хозяйства:
то есть прокидывание инжектящихся значений от того, кто о них знает (читай - конструирует) до того, кто их будет использовать. Сеттеры - это, конечно, тоже тупой код, но их, по счастью, за нас будут писать IDE. Да и не обойтись без них, независимо от IoC.
Не соглашусь. Конвертер этот все равно так или иначе конфигурируется - хотя бы и для уже упомянутых тестов. Затем, стоит подумать о переиспользовании - возможно, один конвертер пригодится нескольким сервисам. Ну и, наконец, если он инжектится, то будет удобно делать апгрейд - заинжектил другой экземпляр, и все. Если инжект объявлен декларативно, то даже перекомпиляция класса сервиса не понадобится. Ну и, к слову, я против идеи использовать рефлекшн только ради отсечения test-only кода, но это совсем параллельная дискуссия...
Ну так он уже за нас написан, со всеми плюшками типа чтения конфигов из XML, инклюдов и т.п. |
| Автор: Stolzen 7.8.2011, 15:42 | ||
Кстати, все-таки интересно было бы услышать аргументы против инжектов для тестирования с помощью рефлексии. Почему это плохо и как лучше тогда отсекать test-only код? |
| Автор: batigoal 7.8.2011, 17:00 |
Это плохо тем же, чем плоха рефлексия в продакшн-коде. Нет проверок в compile-time, ниже скорость работы, возможность проигнорировать области видимости, etc. Кроме того, есть чисто теоретическое соображение: применяя рефлексию, ты тестируешь не "оригинальный" код, а код, динамически тобой измененный для теста, но это уже демагогия. Тем не менее, я рефлексию в тестах часто использую, чтобы меньше кода писать (например, чтобы инстанцировать в тесте объект класса, имя которого можно определить по шаблону из имени класса-теста) А зачем? Фактически, тесты вынуждают тебя применять более модульный и "правильный" дизайн. Дополнительные сеттеры - это, фактически, дополнительная гибкость в настройке бина, я не вижу причин её закрывать. Другое дело, что нередко приходится расширять область видимости членов класса для адекватного их тестирования. Эта проблема имеет несколько решений: наследование, рефлексия, кладка с прибором |
| Автор: Старовъръ 7.8.2011, 19:50 | ||||||||
Короче говоря тема переполнена абстрактными мыслями и сферическими конями, дальше ее развивать похоже нет смысла. |
| Автор: Farmazon 8.8.2011, 06:22 | ||
IoC как раз и придумали чтобы хоть как-то управляться с большими проектами. Есть лучше варианты? |
| Автор: Старовъръ 8.8.2011, 08:04 |
| Для того, чтоб хоть как-то управляться с большими проектами придумали SOAP & MOM. А IoC придумали для уменьшения связанности (coupling) между классами. Про варианты по-лучше я писал выше, можно для начала всю тему прочесть перед постингом в ней ;) |
| Автор: batigoal 8.8.2011, 08:39 | ||||||||||
Старовъръ, не согласен ни по одному пункту. Вообще говоря, все твои аргументы были когда-то и моими аргументами, пока я не поработал в команде, ратующей за хороший дизайн и уверенно владеющей Spring'ом.
Читать их ни капли не сложнее, чем прямой ява-код. IntelliJ IDEA осуществляет прозрачную навигацию, рефакторинг и поиск по Спринговым конфигам, думаю, другие IDE тоже.
Не нужно смешивать гибкость уровня "а давайте сделаем все поля интерфейса настраиваемыми", т.е. гибкость использования и гибкость на уровне кода - это совершенно ортогональные понятия. Добавление сеттеров в бины никак код не усложняет.
Ну естественно, блин - с таким подходом его и не будет. Никто уже и не вспомнит, что где-то там в недрах левого бина уже есть похожий код.
Надо. Тесты - это такой же код, как и весь остальной. А уж время выполнения - это очень важно. Даже если избирательно отключать длинные тесты в процессе девелопмента, они становятся проблемой при разработке билд-процедур.
Э, нет. Я заменяю на моки не тестируемый объект, а его зависимости. |
| Автор: Farmazon 9.8.2011, 07:10 |
| Старовер, ты не прав. MOM и SOAP - не панацея. Добавлено @ 07:25 Слабая связность и сильное сцепление - признаки хорошо спроектированной системы. IoC - хороший паттерн для достижения этих целей. И да, правильное разбиение на инклуды очень упрощает чтение конфигурации. Вон, Alfresco взять к примеру... Там много конфигов, но это не значит что нельзя разобраться со сборкой. |
| Автор: Farmazon 9.8.2011, 07:41 |
| Кстати, есть кроме инклудов вариант использовать иерархичные контексты... SOAP и MOM - у них свои специфичные задачи. SOAP - меж платформенное сетевое взаимодействие, MOM - асинхронный обмен. И они не противоречат IoC и очень хорошо будут работать вместе, этот клей склеит любое приложение. Добавлено @ 07:45 И какой твой критерий больших проектов?... Вот Eclipse - он большой? |