Я верю этому, вопросы задали в некоторых или другом пути, но я еще не получаю его.
Мы делаем проект GWT и мой руководитель проекта запретили для использования GIN/Guice в качестве платформы DI (новые программисты не собираются понимать это, он спорил), таким образом, я пытаюсь сделать DI вручную.
Теперь у меня есть проблема с глубокими графами объектов. Иерархия объектов от UI похожа на это:
AppPresenter-> DashboardPresenter-> GadgetPresenter-> GadgetConfigPresenter
GadgetConfigPresenter путь вниз дерево иерархии объектов имеет несколько зависимостей как CustomerRepository, ProjectRepository, MandatorRepository, и т.д.
Таким образом, GadgetPresenter, который создает GadgetConfigPresenter также, имеет эти зависимости и так далее до точки входа приложения, которое создает AppPresenter.
Вы пишете, что
GadgetPresenter создает GadgetConfigPresenter [.]
вместо прямого создания экземпляров GadgetConfigPresenter
, GadgetPresenter
должен иметь зависимость от абстрактной фабрики , которая может создавать для него экземпляры GadgetConfigPresenter
. Это отправляет внутренние зависимости GadgetConfigPresenter
на фабрику.
При использовании Constructor Injection на всех этапах подключение Poor Man's DI должно выглядеть примерно так (извинения за синтаксис C #):
var customerRepository = new CustomerRepository(/*...*/);
var projectRepository = new ProjectRepository(/*...*/);
var mandatorRepository = new MandatorRepository(/*...*/);
var gadgetConfigPresenterFactory =
new GadgetConfigPresenterFactory(
customerRepository,
projectRepository,
mandatorRepository);
var gadgetPresenter = new GadgetPresenter(gadgetConfigPresenterFactory);
var dashboardPresenter = new DashboardPresenter(gadgetPresenter);
var appPresenter = new AppPresenter(dashboardPresenter);
Обратите внимание, как мы нарушаем цепочка зависимостей часто, гарантируя, что количество зависимостей для каждого потребителя никогда не станет слишком большим.
В принципе, это означает, что вы должны создавать все зависимости во время загрузки, если вы не реализуете стратегию отложенной загрузки .
Такие вещи, как управление временем жизни - это именно та вещь, в которой контейнер DI может быть чрезвычайно полезен, но вполне возможно написать целое приложение, просто следуя шаблонам и принципам DI .
В целом, я бы все же порекомендовал DI-контейнер, если это вообще возможно.
Вы можете выполнять DI с помощью контекстных интерфейсов. Это не сложно и довольно просто.
Контекстный интерфейс - это класс, который предоставляет все привязки из конфигурации модуля guice.
Это пример этого, где я предполагаю, что AppPresenter + DashboardPresenter находится в одном пакете и нуждается в одном «контексте», тогда как GadgetPresenter и GadgetConfigPresenter находятся в другом пакете и нуждаются в другом «контексте». Количество контекстов и способы их обработки полностью зависят от пользователя.
/**
* The dependencies that need to be injected for package1
*/
public interface SomePackageContext {
GadgetPresenter getGadgetPresenter();
GadgetConfigPresenter getGadgetConfigPresenter();
}
/**
* The dependencies that need to be injected for package2
*/
public interface OtherPackageContext {
// These methods can take arguments..
AppPresenter getAppPresenter(Args..);
DashboardPresenter getDashboardPresenter(Args..);
}
/**
* All of the DI needed in our project.
*
* <p>We don't need the two interfaces above, we can put
* everything in this interface if we have a small
* project where layering is not a big issue.
*/
public interface PresenterContext
extends SomePackageContext, OtherPackageContext {
}
public class MockPresenterContext implements PresenterContext {
...
}
public class RealPresenterContext implements PresenterContext {
// This is similar to bind(...) in guice
public AppPresenter getAppPresenter(Args..) {
return new AppPresenter(this, otherargs...);
}
public DashboardPresenter getDashboardPresenter(Args..) {
return new DashboardPresenter(this, otherargs...);
}
public GadgetPresenter getGadgetPresenter() {
return new GadgetPresenter(this);
}
public GadgetConfigPresenter getGadgetConfigPresenter() {
return new GadgetConfigPresenter();
}
}
public class DashboardPresenter {
// @Inject
private final GadgetPresenter gadgetPresenter;
/*
* We inject everything using the SomePackageContext.
*/
public DashboardPresenter(SomePackageContext ctxt) {
this.gadgetPresenter = ctxt.getGadgetPresenter();
}
}