2010-03-11 1 views
7

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

Мы делаем проект GWT, и мой руководитель проекта не разрешил использовать GIN/Guice в качестве рамки DI (новые программисты не поймут это, он утверждал), поэтому я стараюсь сделать DI вручную.

Теперь у меня проблема с графами глубоких объектов. Иерархия объектов из пользовательского интерфейса выглядит следующим образом:

AppPresenter-> DashboardPresenter-> GadgetPresenter-> GadgetConfigPresenter

путь GadgetConfigPresenter вниз по дереву иерархии объектов имеет несколько зависимостей, таких как CustomerRepository, ProjectRepository, MandatorRepository и т.д.

Таким образом, GadgetPresenter, который создает GadgetConfigPresenter, также имеет эти зависимости и т. Д., Вплоть до точки входа приложения, которое создает AppPresenter.

  • Возможно ли, что это руководство должно работать?
  • не означает ли это, что я создаю все зависимости во время загрузки, даже мне они не нужны?
  • будет ли каркас DI, как GIN/Guice, помочь мне здесь?
+2

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

+0

@matt: он совершенно неохотно относится к новым технологиям, и он считает, что новому программисту нужно многому научиться в этом проекте, например, в java-php-мосте, а затем DI - всего лишь волшебство за кулисами, которые они не получат. Я не думаю, что это действительно так. Если рамка DI является единственным решением, я попытаюсь снова убедить его, но мне было бы действительно интересно, если и как это делается вручную. – Fabian

+1

Я бы рекомендовал подходить к этому обсуждению как «посмотреть на все эти ручные работы по прокладке, которые нам нужно сделать в коде, и сравнить его с тем, насколько проще использовать контейнер IoC», –

ответ

8

Вы пишете, что

GadgetPresenter, который создает GadgetConfigPresenter [.]

Вместо непосредственного создания GadgetConfigPresenter экземпляров, GadgetPresenter РЕКОМЕНДУЕМЫМ take a dependency on an Abstract Factory, которые могут создать GadgetConfigPresenter экземпляров для него. Это подталкивает внутренние зависимости GadgetConfigPresenter к заводу.

Использование Constructor Injection всего пути, 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); 

Обратите внимание, как мы разорвать цепочку зависимостей часто , гарантируя, что количество зависимостей для каждого потребителя никогда не станет слишком большим.

В принципе, это означает, что вы должны создавать все зависимости во время загрузки, если только вы не реализуете lazy loading strategy.

Такие вещи, как управление сроками службы, являются именно тем, что контейнер DI может быть чрезвычайно полезным, но вполне возможно написать всего приложение всего лишь following DI patterns and principles.

В целом, я бы по-прежнему рекомендовал контейнер DI, если это вообще возможно.

0

Вы можете использовать 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(); 
    } 
} 
Смежные вопросы