Скажем, у нас есть 1001 клиент, который строит свои зависимости напрямую, а не принимает инъекции. Рефакторинг 1001 не вариант по мнению нашего босса. На самом деле нам даже не разрешен доступ к их источнику, только к файлам классов.
Мы должны «модернизировать» систему, через которую проходят эти 1001 клиент. Мы можем рефакторинг, что все, что нам нравится. Зависимости являются частью этой системы. И некоторые из этих зависимостей мы должны изменить, чтобы иметь новую реализацию.
Мы хотели бы иметь возможность настраивать различные реализации зависимостей для удовлетворения этого множества клиентов. К сожалению, DI не представляется возможным, так как клиенты не принимают инъекции с конструкторами или сеттерами.
Варианты:
1) Измените реализацию службы, которую используют клиенты, чтобы она выполняла то, что нужно клиентам сейчас. Взрыв, мы сделали. Не гибкий Не сложный
2) Рефакторизовать реализацию так, чтобы она делегировала свою работу еще одной зависимости, которую она приобретает через фабрику. Теперь мы можем контролировать, какую реализацию они все используют, путем рефакторинга фабрики.
3) Рефакторизовать реализацию так, чтобы она делегировала свою работу еще одной зависимости, которую она получает через локатор службы. Теперь мы можем контролировать, какую реализацию они все используют, настроив локатор службы, который может быть простоhashmap
строкой для объектов с небольшим продолжением приведения.
4) Что-то, о чем я даже не думал.
Цель:
Минимизируйте ущерб, нанесенный дизайну, перетаскивая старый плохо спроектированный клиентский код в будущее, не добавляя при этом лишней сложности.
Клиенты не должны знать или контролировать реализацию своих зависимостей, но они настаивают на их построении new
. Мы не можем контролировать, new
но мы контролируем класс, который они строят.
Мой вопрос:
Что я не учел?
вам действительно нужна возможность настройки между различными реализациями? С какой целью?
Ловкость. Много неизвестных. Менеджмент хочет потенциала для изменений. Только потерять зависимость от внешнего мира. Также тестирование.
Вам нужна механика времени выполнения или просто механика времени компиляции для переключения между различными реализациями? Почему?
Механика времени компиляции вполне вероятна. За исключением тестирования.
какая гранулярность вам нужна для переключения между реализациями? Все вместе? За модуль (каждый из которых содержит группу классов)? В классе?
Из 1001 только один запускается через систему одновременно. Изменение того, что все клиенты используют одновременно, вполне вероятно. Индивидуальный контроль над зависимостями, вероятно, важен, хотя.
кому нужно управлять выключателем? Только ваша / ваша команда разработчиков? Администратор? Каждый клиент по-своему? Или разработчики поддержки для кода клиента? Итак, насколько простой / надежной / надежной должна быть механика?
Dev для тестирования. Администратор как внешние аппаратные зависимости меняются. Это должно быть легко проверить и настроить.
Наша цель - показать, что система может быть быстро переделана и модернизирована.
Фактический вариант использования для реализации переключения?
Во-первых, некоторые данные будут предоставляться программным обеспечением до тех пор, пока аппаратное решение не будет готово.
источник
Ответы:
Ну, я не уверен, что полностью понимаю технические детали и их точные отличия от поддерживаемых вами решений, но ИМХО вам сначала нужно выяснить, какая гибкость вам действительно нужна.
Вопросы, которые вы должны задать себе:
вам действительно нужна возможность настройки между различными реализациями? С какой целью?
Вам нужна механика времени выполнения или просто механика времени компиляции для переключения между различными реализациями? Почему?
какая гранулярность вам нужна для переключения между реализациями? Все вместе? За модуль (каждый из которых содержит группу классов)? В классе?
кому нужно управлять выключателем? Только ваша / ваша команда разработчиков? Администратор? Каждый клиент по-своему? Или разработчики поддержки для кода клиента? Итак, насколько простой / надежной / надежной должна быть механика?
Имея в виду ответы на эти вопросы, выберите самое простое решение, которое вы можете придумать, которое обеспечивает необходимую гибкость. Не используйте гибкость, в которой вы не уверены, «на всякий случай», если это требует дополнительных усилий.
В ответ на ваши ответы: если у вас есть хотя бы один реальный вариант использования, используйте его для проверки ваших проектных решений. Используйте этот вариант, чтобы узнать, какое решение лучше всего подходит для вас. Просто попробуйте, если «фабрика» или «сервисный локатор» предоставит вам то, что вам нужно, или если вам нужно что-то еще. Если вы считаете, что оба решения одинаково хороши для вашего случая, бросьте кубик.
источник
Просто чтобы убедиться, что я правильно понял. Например, у вас есть сервис, состоящий из нескольких классов
C1,...,Cn
и группы клиентов, которые напрямую звонятnew Ci(...)
. Поэтому я думаю, что согласен с общей структурой вашего решения, которая заключается в создании новой внутренней службы с некоторыми новыми классамиD1,...,Dn
, которые хороши и современны, и внедряют их зависимости (разрешают такие зависимости через стек), а затем переписывают,Ci
чтобы ничего не делать, кроме как создавать и Delgate toDi
. Вопрос в том, как это сделать, и вы предложили несколько способов2
и3
.Чтобы дать аналогичное предложение
2
. Вы можете использовать внедрение зависимостей какDi
внутри, так и внутри, а затем создать нормальный составной кореньR
(используя каркас, если считаете это необходимым), который отвечает за сборку графа объектов. ПихайтеR
за статичный завод и дайте каждомуCi
пройтиDi
через это. Так, например, вы могли бы иметьПо сути, это ваше решение 2, но оно собирает все ваши фабрики в одном месте вместе с остальной частью внедрения зависимости.
источник
getInstance()
?Начните с простых, ничего необычных реализаций.
Если вам позже потребуется создать дополнительные реализации, вопрос в том, когда будет принято решение о реализации.
Если вам нужна гибкость «времени установки» (каждая установка клиента использует одну статическую реализацию), вам все равно не нужно делать что-то необычное. Вы просто предлагаете разные DLL или SO (или любой другой формат вашей библиотеки). Клиенту просто нужно положить правильный в
lib
папку ...Если вам нужна гибкость во время выполнения, вам просто понадобится тонкий адаптер и механизм выбора реализации. Используете ли вы контейнер фабрики, локатора или IoC, в основном спорный вопрос. Единственными существенными различиями между адаптером и локатором являются A) Именование и B) Является ли возвращаемый объект одноэлементным или выделенным экземпляром. И большая разница между контейнером IoC и фабрикой / локатором заключается в том, кто кого называет . (Часто это вопрос личных предпочтений.)
источник