2012-12-20 10 views
6

Sono di fronte a un problema di dipendenza ciclica durante la creazione del seguente progetto MVP (per winforms) utilizzando il contenitore windsor.Problema di riferimento ciclico nel pattern MVP utilizzando il castello di Windsor per l'iniezione di dipendenza

mio presentatore dipende dalla vista e modello:

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

mio punto di vista dipende dal presentatore:

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; 
} 

sto registrando tutti i componenti con il castello di Windsor (in una classe di composizione di root separato) come di seguito:

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>()); 

La risoluzione della vista solleva il problema del ciclico re ferenza problema:

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

Una possibile soluzione potrebbe essere quella di rimuovere l'iniezione costruttore dal vista e risolvere il presentatore separatamente. Ma questo mi fa usare il contenitore in due posti che non stavo cercando di fare e probabilmente è sbagliato.

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

Esiste una soluzione migliore a questo. Sto facendo qualcosa di sbagliato in MVP stesso?

+0

possibile duplicato: http://stackoverflow.com/questions/1783124/castle-ioc-resolving-circular-references – Roubachof

risposta

4

Esistono diverse soluzioni a questo problema, ma tutte interrompono il ciclo di dipendenze rimuovendo il relatore o la vista come dipendenza del costruttore.

La soluzione più semplice sarebbe quella introducendo la vista come proprietà sul presentatore:

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

public IView View { get; set; } 

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

rovescio della medaglia è che è necessario configurare ciascun presentatore come viene iniettato la vista, così si potrebbe anche spostare questo per una base di classe:

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

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

Un'altra opzione è quella di iniettare una fabbrica di presentatore nella vista e richiedere da lì:

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

Il lato negativo è che questo costruttore chiama una fabbrica, che non è la cosa più pulita da fare, ma gestibile.

+0

Ho usato la prima opzione suggerita da te e funziona per me. –

+0

Penso che questo sia scarso Di causa Spostare l'iniezione dalla radice composita ad un altro punto. – Kenji

0

Creare una fabbrica per istanziare i presentatori. La tua vista (il WinForm) userà la fabbrica nel constuctor. Probabilmente potresti usare la Typed Factory Facility, ovvero dovrai solo definire l'interfaccia per la fabbrica di presenter e lasciare che la struttura faccia il resto.

+0

sarebbe possibile ottenere un codice di esempio? –