2014-09-10 33 views
1

我的工廠正在使用方法注入,因爲我認爲這是迄今爲止最好的方法。此外,我不確定在從屬對象中調用它的Create方法後它是一件好事。正確使用參數化的Factory.Create()方法使用DI

在繼續使用參數化工廠Create方法時,我可能會考慮的唯一方法是直接在MainPresenter中注入依賴關係,以便它可以提供方法的依賴關係,並且我不喜歡它。它不喜歡它,因爲它不是MainPresenter,它取決於ICustomerManagementViewICustomerDetailPresenterFactory,這是它的依賴關係。所以我覺得我這樣做破壞了我自己的代碼。

MainPresenter

public class MainPresenter : Presenter<IMainView>, IMainViewUiHandler { 
    public MainPresenter(IMainView view 
     , ICustomerManagementPresenterFactory customerManagementFactory) 
     : base(view) { 
     this.customerManagementPresenterFactory = customerManagementPresenterFactory; 
    } 

    public void ManageCustomers() { 
     // The following line is causing trouble. 
     // As you can see per the ICustomerManagementPresenterFactory code sample, 
     // the Create() method takes two parameters: 
     // 1. ICustomerManagementView, and 
     // 2. ICustomerDetailPresenterFactory 
     // Hence I have to provide the dependencies manually, I guess. Which is 
     // something to avoid at any cost.    
     var customerManagementPresenter = customerManagementPresenterFactory.Create(); 
     customerManagementPresenter.ShowView(); 
    } 
} 

ICustomerManagementPresenterFactory

public interface ICustomerManagementPresenterFactory { 
    // Here. Though I ask Ninject to inject my dependencies, I need to 
    // provide values to the parameters when calling the method from within 
    // the MainPresenter class. The compiler won't let me do otherwise! And 
    // this makes sense!... 
    [Inject] 
    CustomerManagementPresenter Create(ICustomerManagementView view 
            , ICustomerDetailPresenterFactory factory); 
} 

IMainView

public interface IMainView : IView, IHasUiHandler<IMainViewUiHandler> { 
} 

IMainViewUiHandler

public interface IMainViewUiHandler : IUiHandler { 
    void ManageCustomers(); 
} 

IUiHandler

public interface IUiHandler { 
} 

IHasUiHandler

public interface IHasUiHandler<H> where H : IUiHandler { 
    H Handler { set; } 
} 

的MainForm

public partial class MainForm : Form, IMainView { 
    public MainForm() { InitializeComponent(); } 

    public IMainViewUiHandler Handler { private get { return handler; } set { setHandler(value); } } 
} 

CompositionRoot

public class CompositionRoot { 
    private CompositionRoot() { } 

    public static IKernel BuildObjectGraph() { 
     IKernel kernel = new StandardKernel(); 
     BindFactories(kernel); 
     BindViews(kernel); 
    } 

    private static void BindFactories(IKernel kernel) { 
     kernel.Bind(services => services 
      .From(AppDomain.CurrentDomain 
       .GetAssemblies() 
       .Where(a => !a.FullName.Contains("Tests"))) 
      .SelectAllInterfaces() 
      .EndingWith("Factory") 
      .BindToFactory() 
     ); 
    } 

    private static void BindViews(IKernel kernel) { 
     kernel.Bind(services => services 
      .From(AppDomain.CurrentDomain 
       .GetAssemblies() 
       .Where(a => a.FullName.Contains("Windows") 
         && !a.FullName.Contains("Tests")) 
      .SelectAllClasses() 
      .EndingWith("Form") 
      .BindSelection((type, baseType) => type 
       .GetInterfaces() 
       .Where(iface => iface.Name.EndsWith("View")) 
      ) 
     ); 
    } 
} 

所以我在想,是不是最好的實現ICustomerManagementPresenterFactoryCompositionRoot中的綁定與它的實施者,這樣我就可以提供通過構造函數注入這些依賴於Create不應再採取任何論據的方法,否則我應該採取其他辦法嗎?

我喜歡編寫一個簡單的界面,Ninject對我來說都是爲工廠做的,並且不需要代碼來構建所需類型的實例。另外,當要創建的類的構造函數使用構造函數注入時,似乎不可能將一個簡單的工廠接口綁定爲工廠,而且需要手動實現工廠接口。

我得到了什麼對/錯?

回答

1

事實上,您根本不需要將參數傳遞給工廠Create方法 - 除非它們是需要通過「向下」傳遞的參數,因爲它們不能綁定到組合根中(for例如輸入值)。但是,將這些參數傳遞給構造函數通常是一種代碼味道。大多數情況下,這是一個好主意,把這些參數傳遞給方法,而不是構造函數(例如:Adder.Add(5,3);,不new Adder(5, 3).ComputeResult();

現在考慮下面的例子,這工作完全正常:

public class Dependency1 { } 

public interface IDependency2 { } 
public class Dependency2 : IDependency2 { } 

public interface IBar { } 

public class Bar : IBar 
{ 
    public Bar(Dependency1 d1, IDependency2 d2) { } 
} 

public interface IBarFactory 
{ 
    IBar Create(); 
} 


var kernel = new StandardKernel(); 
kernel.Bind<IBarFactory>().ToFactory(); 
kernel.Bind<IBar>().To<Bar>(); 
kernel.Bind<Dependency1>().ToSelf(); 
kernel.Bind<IDependency2>().To<Dependency2>(); 

var factory = kernel.Get<IBarFactory>(); 
var bar = factory.Create(); 

bar.Should().BeOfType<Bar>(); 

即使Bar需要兩個構造參數,生成IBarFactoryCreate()方法沒有指定所以沒問題,ninject會自動解決。

現在讓我給你一個例子什麼.ToFactory()實際上導致。考慮工廠:

public interface ISomeFactory 
{ 
    ISomething Create(string parameter1); 
} 

會導致(注:它是由攔截器實現的,而不是由編織,所以這個例子是一個simplificiation):

public class SomeFactory : ISomeFactory 
{ 
    private readonly IResolutionRoot resolutionRoot; 

    public SomeFactory(IResolutionRoot resolutionRoot) 
    { 
     this.resolutionRoot = resolutionRoot; 
    } 

    public ISomething Create(string parameter1) 
    { 
     this.resolutionRoot.Get<ISomething>(new ConstructorArgument("parameter1", parameter1); 
    } 
} 

ConstructorArgument告訴ninject傳遞價值parameter1添加到名爲「parameter」的ctor參數中。

所有其他參數「像往常一樣」被解析。如果無法解析構造函數參數(既不作爲參數傳遞,也不作爲綁定傳遞),ninject將拋出一個異常,指出參數無法解析。