2015-07-11 47 views
0

我目前有一个业务类,其构造函数需要一个存储库实现。这个存储库有多个实现。在运行时,我想确定应该提供哪个存储库实现。我是使用DI框架和Autofac的新手。这是我的存储库实现。使用Autofac向我的业务类注入正确的类型

public interface IRepository 
{ 
    string GetData(); 
} 

public class ServiceRepository : IRepository 
{ 
    ///implementation.. 
} 

public class DatabaseRepository : IRepository 
{ 
    ///implementation.. 
} 



public class BusinessClass 
{ 
    public BusinessClass(IRepository repo) 
    { 
    //assign to local variable 
    } 
} 

正如你所看到的,IRepository有多个实现。然而,我想在运行时决定哪一个应该被传入我的业务类。我通过这些例子herehere,但他们似乎不解释如何实现这一要求。此时更改界面设计不是一种选择。我是否还需要实现一个工厂类来选择性地解析正确的类型?

+0

你注册,你要执行时,基于配置文件或应用程序启动任何插件系统,如果你有一个。如果你需要“动态地”改变这些东西(IMO有点臭),那么你需要一个工厂。 – MikeSW

+0

为什么会有点臭?并不矛盾你所说的话,而只是试图理解为什么。这个业务类取决于数据的外部服务。前端会根据用户的选择向其发送数据源。有时它可能是webservice-A。在其他时候,它可能是webservice-B,有时候它可能是一个数据库。复制这些选择中的每一个的业务类,就像Autofac只有一个类需要解决似乎我们正在润湿现有代码的干燥程度以适应DI框架。毋庸赘言,这些服务不在我的控制之下来改变。 – user20358

+1

然后,您的业务服务应该将工厂视为依赖项,并且该工厂将通过autofac注入。 – MikeSW

回答

0

有几种更清洁的方式,而不是使用工厂。

  • 您可以在使用Autofac解析所有IRepositories时使用责任链模式,然后每个存储库都可以告诉您他们是否有责任处理该请求。
  • 你可以把它打开,说我有一个存储库列表,我需要一个服务,它需要这些存储库并根据一组业务规则(本质上是一个工厂)返回一个特定的存储库。虽然这种方法使解决方案有点单元测试友好。

只为你一些选项来考虑:)

0

你可以在这里使用工厂模式,但你并不需要创建一个专用的工厂类,函数功能就足够了。你的业务层不应该意识到这个切换逻辑,它应该去应用层控制器。

一个可能的例子:

你的控制器

public void SomeController(Func<string, IBusinessService> serviceFactory) 
{ 
    this.serviceFactory = serviceFactory; 
} 
... 
//somewhere inside controller 
serviceFactory("database").SomeBusinessLogic(); 
... 

和Autofac登记:

builder 
.RegisterType<ServiceRepository>() 
.Named<IRepository("service"); 

builder 
.RegisterType<DatabaseRepository>() 
.Named<IRepository>("database"); 

builder 
.Register<Func<string,IBusinessService>>(cx => 
{ 
    var componentContext = cx.Resolve<IComponentContext>(); 
    return (key => 
     new BusinessService(componentContex.ResolveNamed<IRepository>(key)) 
    ); 
} 
) 
.As<Func<string, IBusinessService>>();