Вы можете использовать синглтон вместо того, чтобы вводить свои зависимости явно, но имейте в виду, что этот дизайн приводит к менее тестируемому коду и высокофункциональной связи между компонентами.Другие экосистемы решили эту проблему, вводя средства для внедрения зависимостей декларативным способом, благодаря структурам, которые предоставляют механизм для замены фактических зависимостей на «тестовые двойники».Узнайте, как Spring MVC работает с Java-приложениями.
Если вы уверены, что это именно то, что вам нужно, вы можете использовать аналогичный (но все же менее гибкий) подход, реализующий шаблон «поиска сервисов», который состоит в следующем:единственная точка, которая содержит указатели на экземпляры «инъецируемых» объектов
ServiceLocator::inject<Screen*>(new Screen () , "screen1")
//
...
//
Screen* s = ServiceLocator::getInstance<Screen*>("screen1")
Таким образом, вы можете избежать передачи указателей вокруг и в то же время быть более разъединенными.Теперь предположим, что у вас есть MockScreen, который наследуется от Screen.Предположим также, что вы хотите протестировать метод int MyClass :: workWithScreen (), который зависит от экземпляра Screen, на который ссылается метка "screen1".Вы можете написать свой тест как
Myclass unitUnderTest;
ServiceLocator::inject<Screen*>(new MockScreen () , "screen1");
int result = unitUnderTest.workWithScreen()
assert ....
Я оставлю вас в качестве упражнения по реализации локатора службы!
Имейте в виду, что таким образом вы также вводите в свой кодНедостатки внедрения зависимостей: хуже всего то, что вы теряете контроль над дизайном компоновки вашего компонента, каждый объект может получить доступ к каждому объекту.Это не большая проблема, когда вы разрабатываете некоторый обработчик API REST, который основан на надежном и хорошо известном архитектурном паттерне (controller -> service -> repository -> db и затем возвращается), но вы должны быть осторожны в других контекстах!