2012-12-20 14 views
6

Mam do czynienia z problemem cyklicznej zależności podczas tworzenia następującego projektu MVP (dla winform) przy użyciu kontenera windsor.Cykliczne odniesienie w wzorcu MVP przy użyciu zamku Windsor dla iniekcji zależnej

Moja prezenter zależy na widoku i modelu

ConcretePresenter(IView view, IModel model) 
{ 
    this.view = view; 
    this.model = model; 
} 

Moim zdaniem zależy od prezentera:

ConcreteView(ConcretePresenter presenter) 
{ 
    //actual requirement that the presenter use the current instance of the view and a model object 
    //new presenter(this, new model()) 
    this.presenter = presenter; 
} 

ja rejestracji wszystkie składniki za pomocą Zamek Windsor (w oddzielnej klasie korzenia kompozycji) poniżej:

IWindsorContainer container; 
container = new WindsorContainer(); 
container.Register(Component.For<ConcretePresenter>().ImplementedBy<ConcretePresenter>()); 
container.Register(Component.For<IModel>().ImplementedBy<ConcreteModel>());      
container.Register(Component.For<IView>().ImplementedBy<ConcreteView>()); 

Rozwiązanie problemu podnosi kwestię cyklicznego ponownego Ferenc problem:

container.Resolve<ConcreteView>(); //doesn't resolve because of cyclic dependency 

Możliwym rozwiązaniem byłoby usunięcie zastrzyk konstruktora z widoku prezentera i rozwiązywać oddzielnie. Ale to powoduje, że używam kontenera w dwóch miejscach, czego nie chciałem i prawdopodobnie się mylę.

ConcreteView() 
{ 
    container.Resolve<ConcretePresenter>(); //resolving at 2 different points  
} 

Czy istnieje lepsze rozwiązanie tego problemu. Czy robię coś złego w samym MVP?

+0

możliwy duplikat: http://stackoverflow.com/questions/1783124/castle-ioc-resolving-circular-references – Roubachof

Odpowiedz

4

Istnieje kilka rozwiązań tego problemu, ale wszystkie z nich przerywają cykl zależności, usuwając prezentera lub widok z roli zależności konstruktora.

Najprostszym rozwiązaniem byłoby wprowadzając pogląd jako własność na prezentera:

// Presenter 
ConcretePresenter(IModel model) 
{ 
    this.model = model; 
} 

public IView View { get; set; } 

// View 
ConcreteView(ConcretePresenter presenter) 
{ 
    this.presenter = presenter; 
    this.presenter.View = this; 
} 

Wadą jest to, że trzeba skonfigurować każdy prezenter jak to jest wstrzykiwany do widzenia, więc można również przenieść to do bazy klasa:

// View 
ConcreteView(ConcretePresenter presenter) : base(presenter) 
{ 
} 

BaseView(IPresenter presenter) 
{ 
    Contract.Requires(presenter != null); 
    presenter.View = this; 
    this.Presenter = presenter; 
} 

Inną opcją jest wstrzykiwać fabrykę prezentera do widzenia i poprosić go stamtąd:

// View 
ConcreteView(IPresenterFactory factory) 
{ 
    this.presenter = factory.CreatePresenterFor(this); 
} 

Minusem jest to, że ten konstruktor nazywa fabrykę, co nie jest najczystszą rzeczą do zrobienia, ale można nią zarządzać.

+0

Użyłem pierwszej opcji sugerowanej przez Ciebie i działa ona dla mnie. –

+0

Myślę, że to jest słabe Di spowodować Przenieś zastrzyk z Composite root do innego punktu. – Kenji

0

Utwórz fabrykę do tworzenia prezentacji prezenterów. Twój widok (WinForm) użyje fabryki w konduktorze. Najprawdopodobniej możesz skorzystać z Wirtualnego zakładu produkcyjnego - oznacza to, że musisz tylko zdefiniować interfejs dla fabryki prezenterów i pozwolić, aby obiekt wykonał resztę.

+0

Czy można uzyskać przykładowy kod? –