灵感来自Mark Seemann's post: Pattern Recognition: Abstract Factory or Service Locator?
我希望写一个像这样的抽象工厂:
public interface IAbstractFactory {
T Create<T>();
}
然后,使用Ninject绑定它,如下所示:
IKernel kernel = new StandardKernel();
kernel.Bind<IAbstractFactory>().ToFactory();
然后,可以按如下方式使用它:
public class CustomerServiceIndicatorsModel {
public CustomerServiceIndicatorsModel(IAbstractFactory factory) {
this.emailIndicatorA = factory.Create<EmailIndicatorA>();
this.emailIndicatorB = factory.Create<EmailIndicatorB>();
this.emailIndicatorC = factory.Create<EmailIndicatorC>();
}
}
同样,我没有在任何地方引用Ninject的内核,这很有效。内核仅在绑定的Global.asax.cs
文件中引用。
它可以被视为抽象工厂模式的可接受实现吗?
我很难找到这种模式的主旨。我清楚地理解Factory
模式是一个委托类,它创建给定类型的实例。
public interface IEmailIndicatorAFactory {
EmailIndicatorA Create();
}
然后,当我使用Ninject绑定它ToFactory()
时,它将创建EmailIndicatorA
的实例。
如何使用Ninject绑定IAbstractFactory<T>
,因为每种类型:
IAbstractFactory<EmailIndicatorA>
IAbstractFactory<EmailIndicatorB>
IAbstractFactory<EmailIndicatorC>
被认为是一种完全具体的类型。我无法找到使用Ninject
绑定它的方法。
如果作为回报,我不会写这样的界面有什么好处:
public interface EmailIndicatorAFactory : IAbstractFactory<EmailIndicatorA> { }
public interface EmailIndicatorBFactory : IAbstractFactory<EmailIndicatorB> { }
public interface EmailIndicatorCFactory : IAbstractFactory<EmailIndicatorC> { }
在@PrestonGuillot发表评论后,由于我使用的是通用ServiceLocator
方法,而AbstractFactory
实现了Create<T>()
而不是Abstract Factory
。 1}}使用非通用的Create()
方法。
感谢您指出,@ PrestonGuillot! =)
也许我在这里过于复杂......所以这就是我的模特:
EmailIndicator
public abstract EmailIndicator {
int EmailCount { get; set; }
DateTime OldestDateTimeReceived { get; set; }
}
EmailIndicatorA
public class EmailIndicatorA : EmailIndicator { }
EmailIndicatorB
public class EmailIndicatorB : EmailIndicator { }
EmailIndicatorC
public class EmailIndicatorC : EmailIndicator { }
IEmailIndicatorRepository
public interface IEmailIndicatorRepository<T> where T : EmailIndicator {
T GetIndicator();
}
public class EmailIndicatorARepository : IEmailIndicatorRepository<EmailIndicatorA> {
public EmailIndicatorARepository(IExchangeService service
, IExchangeConfiguration configuration
, INetworkCredentialFactory credentialFactory) {
exchangeService = service;
exchangeService.Url = configuration.ExchangeUri;
exchangeService = credentialFactory.Create(configuration.Login, configuration.Password);
}
EmailIndicatorA GetIndicator() {
// Code to query Exchange through its Web services here...
}
}
还存在另外两个这样的存储库,因为我必须在我的应用程序中查询三个不同的Exchange服务器。
我相信使用Abstract Factory
还有空间,因为我仍然在学习这种模式,但在我的情况下,我还是不知道如何实现它。
如果没有针对指标本身,也许我终于可以掌握Abstract Factory
我的回忆。
就我的理解而言,这是我尝试解决问题的第一步:
IRepositoryFactory
public interface IRepositoryFactory<T> where T : class, new() {
T Create();
}
IEmailIndicatorARepositoryFactory
public interface IEmailIndicatorARepositoryFactory
: IRepositoryFactory<EmailIndicatorARepository> {
EmailIndicatorARepository CreateEmailIndicatorARepository();
}
IEmailIndicatorBRepositoryFactory
public interface IEmailIndicatorBRepositoryFactory
: IRepositoryFactory<EmailIndicatorBRepository> {
EmailIndicatorBRepository CreateEmailIndicatorBRepository();
}
抽象工厂?
public abstract IEmailIndicatorRepositoryFactory
: IEmailIndicatorARepositoryFactory
, IEmailIndicatorBRepositoryFactory
, IEmailIndicatorCRepositoryFactory {
EmailIndicatorARepository CreateEmailIndicatorARepository() { // create instance here... }
EmailIndicatorBRepository CreateEmailIndicatorBRepository() { // create instance here... }
EmailIndicatorCRepository CreateEmailIndicatorCRepository() { // create instance here... }
}
这是一种更好的方法吗?
我在这里迷茫和困惑。
答案 0 :(得分:1)
我发现Wikipedia article的图表很有启发性。
我认为这个名字&#34;抽象工厂&#34;在.net / c#世界中有点误导。如果语言不支持接口或您想要共享实现(但请记住favor composition over inheritance),则只需要abstract class
。
既然你提到马克·西曼,我想提炼一下他对IoC和工厂的一些帖子的解释:
所以给出你的例子,这将是:
public interface IEmailIndicatorFactory
{
IEmailIndicator Create();
}
有三个实现,一个用于EmailIndicatorA
,EmailIndicatorB
和EmailIndicatorC
。现在要使参数变得重要,EmailIndicator
需要一个特定于EmailIndicatorA
,(或B,C)的依赖项。我们说它需要IServiceA
:
internal class EmailIndicatorA : IEmailIndicator
{
private readonly IServiceA serviceA;
public EmailIndicatorA(IServiceA serviceA)
{
this.serviceA = serviceA;
}
(...)
}
现在应该有一个相应的工厂接收EmailIndicatorA
:
internal class EmailIndicatorAFactory : IEmailIndicatorFactory
{
private readonly IServiceA serviceA;
public EmailIndicatorAFactory(IServiceA serviceA)
{
this.serviceA = serviceA;
}
public IEmailIndicator Create()
{
return new EmailIndicatorA(this.serviceA);
}
}
那就是它。如果EmailIndicatorA
有其他依赖关系,则应将它们注入EmailIndicatorAFactory
。
现在,执行所有这些代码的好处是快速失败。
所有其他问题都可以通过正确使用.ToFactory()
绑定和接口来解决,这些绑定和接口不是通用的,而是特定的(基本上与上面的抽象工厂基本相同!)。
我认为你应该仔细权衡专业人士的角色。
马克还说他很少再使用IoC容器了。相反,他最常喜欢穷人的爱情。请参阅this post。我认为马克非常擅长指出职业选手,并且阅读他的帖子非常有教育意义。我不同意他的所有结论,但TBH我很乐意和他一起工作一段时间(不仅仅是几周,更长),然后看我是否同意或不
话虽如此,我想为您提供另一种处理抽象工厂模式用例的方法。既然我已经将它发布在SO上,那么除了link it :)
之外别无选择。作为最后一点,我不知道任何具有Func<>
的IoC容器或Ninject&#39; .ToFactory()
之类的接口工厂,这些工厂可以提前实例化依赖关系。只有在您执行Func<>
或调用IFooFactory.CreateFoo()
方法后才会执行此操作。
因此,自动生成的工厂尚未解决快速失败的问题。
但是,已经完成的是某些容器具有验证方法,这些验证方法可以验证类型是否可以实例化,并且没有Captive Dependencies。例如Simple Injector