2014-03-27 40 views
0

我想创建一个PresenterFactory将负责,很明显,为创建演示实例。如何在泛型中使用工厂模式?

基于对这个问题提供了代码示例:

How to Moq this view?

和@ Pacane的回答,我以为我会走这条路:

PresenterFactoryTests

[TestClass] 
public class PresenterFactoryTests { 
    [TestClass] 
    public class Instance : PresenterFactoryTests { 
     [TestMethod] 
     public void ReturnsInstantialized() {     
      // arrange 
      Type expected = typeof(PresenterFactory); 

      // act 
      PresenterFactory actual = PresenterFactory.Instance; 

      // assert 
      Assert.IsNotNull(actual); 
      Assert.IsInstanceOfType(actual, expected); 
     } 

     [TestMethod] 
     public void ReturnsSame() { 
      // arrange 
      PresenterFactory expected = PresenterFactory.Instance; 

      // act 
      PresenterFactory actual = PresenterFactory.Instance; 

      // assert 
      Assert.AreSame(expected, actual); 
     } 
    } 

    [TestClass] 
    public class Create : PresenterFactoryTests { 
     [TestMethod] 
     public void ReturnsAuthenticationPresenter { 
      // arrange 
      Type expected = typeof(IAuthenticationPresenter); 

      // act 
      IAuthenticationPresenter actual = 
       PresenterFactory 
        .Instance 
        .Create<IAuthenticationPresenter, IAuthenticationView>(
         new MembershipService()); 

      // assert 
      Assert.IsInstanceOfType(actual, expected); 
     } 

     // Other tests here... 
    } 
} 

Presenter工厂

public sealed PresenterFactory { 
    private PresenterFactory() { } 

    public static PresenterFactory Instance { get { return getInstance(); } } 

    P Create<P, V>(params object[] args) where P : IPresenter<V> where V : IView { 
     V view = (V)Activator.CreateInstance<V>(); 
     return Activator.CreateInstance(typeof(P), view, args); 
    } 

    private static PresenterFactory getInstance() { 
     if (instance == null) instance = new PresenterFactory(); 
     return instance; 
    } 

    private static PersenterFactory instance; 
} 

ApplicationPresenter

public class ApplicationPresenter : Presenter<IApplicationView>, IApplicationPresenter { 
    public ApplicationPresenter(IApplicationView view, PresenterFactory presenters) 
     : base (view) { 
     Presenters = presenters; 

     // other initializing stuff here... 
    }  
} 

然而,因为类型的限制,似乎我不能这样做,因为在测试中陈述上述。

在我的PresenterFactoryTests.Create.ReturnsAuthenticationPresenter测试方法中,当我使用接口作为类型参数时,它会在运行时进行编译和抛出,因为Activator.CreateInstance无法创建接口的实例。

除此之外,如果我输入的具体类型,它抱怨说,它不能明确地转换类型,我喜欢的类型的限制,虽然两者实现给定的接口。

ApplicationPresenter需要PresenterFactory,我将通过其构造函数注入它,以便应用程序可以实例化所有可用的演示者,具体取决于用户要求的功能。

我错过了什么?

+1

我不知道你是否使用依赖注入器,但我个人使用Ninject的扩展为你生成工厂。 https://github.com/ninject/ninject.extensions.factory/wiki/Factory-interface – Pacane

+0

感谢您指出我出去Ninject。我已经在过去使用过它。在你分享之前,我没有想到它。 –

回答

2

我认为你需要一个更通用的参数 - 具体类型的观点,因为你需要2种具体类型(图和演示者能够创建他们)和视图的接口类型:

P Create<P, V, IV>(params object[] args) 
     where P : IPresenter<V> where V :IV, IV: IView { 
+0

+1提出一个整洁的解决方案。有时更简单的解决方案是我们认为最不重要的解决方案。 = P我很担心易用性。我个人认为,给予多种类型的参数对于代码重用来说是很容易的,因为对于那些可能不知道工厂工作原理的人来说,因此我想到了注册哪些增加了,恕我直言,复杂性而不是使用。我发现程序员使用多个类型参数以及在'args'对象数组中提供正确的参数更有价值和自然。你对这个话题有什么想法? –

+0

@WillMarcouiller - 用于创建对象,我将使用注释中提到的DI容器。如果将此用于工厂,我不会花时间隐藏代码中的类型,因为使用仅限于代码的很小部分,并且“设置我的依赖关系”代码已经有很多“魔力”。对于其他用法 - 如果类型不能被编译器自动检测到,我会尝试找到另一个解决方案。 –

+0

@WillMarcouiller注意:您可以尝试将其发布到http://CodeReview.stackexchange.com,看看是否有更好的解决方案。我个人不喜欢你的方法如何不会提供关于参数会发生什么的暗示(它们会传递给一个/两个/哪一个类型的构造函数,会发生一些神奇的匹配,......)。也许一些流体接口会更好地工作'使用().ViewParm(viewConstructorArgs).PresenterParm(args).Build()' –