6

我有一个 wcf 服务,在客户端我有:

var service = new ServiceReference1.CACSServiceClient()

实际的服务代码是:

public CACSService() : this(new UserRepository(), new BusinessRepository()) { }

public CACSService(IUserRepository Repository, IBusinessRepository businessRepository)
{
     _IRepository = Repository;
     _IBusinessRepository = businessRepository;
}

所以,这一切都很好,但我不喜欢我如何同时更新所有存储库,因为客户端代码可能不需要UserRepository更新,只对更新BusinessRepository. 那么,有没有办法向该代码传递一些东西:
var service = new ServiceReference1.CACSServiceClient()
根据调用服务的代码或我在为我的实体框架设计存储库时需要进行的任何其他建议来告诉它要新建哪个存储库。谢谢

4

4 回答 4

16

纯 DI 的美妙之处在于您不必担心依赖项的生命周期,因为这些依赖项由提供它们的人(DI 容器或您自己编写的其他代码)为您管理。

(顺便说一句,您应该摆脱当前的Bastard Injection构造函数。扔掉无参数构造函数并保留显式宣传其依赖关系的构造函数。)

保持这样的构造函数,并根据需要使用 _IRepository 和 _IBusinessRepository:

public CACSService(IUserRepository Repository, IBusinessRepository businessRepository) 
{ 
    _IRepository = Repository; 
    _IBusinessRepository = businessRepository; 
} 

如果您担心在运行时不需要这些存储库之一,您可以注入一个延迟加载实现,例如 IUserRepsository,而不是您最初想到的真实存储库。

让我们假设 IUserRepository 看起来像这样:

public interface IUserRepository
{
    IUser SelectUser(int userId);
}

您现在可以像这样实现延迟加载实现:

public class LazyUserRepository : IUserRepository
{
    private IUserRepository uRep;

    public IUser SelectUser(int userId)
    {
        if (this.uRep == null)
        {
            this.uRep = new UserRepository();
        }
        return this.uRep.SelectUser(userId);
    }
}

当您创建 CACService 时,您可以通过将 LazyUserRepository 注入其中来实现,这样可以确保真正的 UserRepository 仅在需要时才会被初始化。

这种方法的美妙之处在于,在您需要它之前,您不必这样做。通常,这实际上是不必要的,因此能够将此类优化推迟到真正需要它们之前是件好事。

我首先在这里这里描述了延迟依赖 的技术。

于 2010-02-27T21:02:43.317 回答
0

您可以将它们延迟加载到它们的属性中,而不是在构建时实例化(“更新”)存储库。这将允许您保留第二个构造函数,但让您的第一个构造函数什么也不做。

然后,用户可以根据需要分配这些,否则。

例如:

public class CACSService
{
    public CACSService() {}

    public CACSService(IUserRepository Repository, IBusinessRepository businessRepository)
    {
        _IRepository = Repository;
        _IBusinessRepository = businessRepository;
    }

    private IUserRepository _IRepository;
    public IUserRepository Repository
    {
        get {
             if (this._IRepository == null)
                  this._IRepository = new UserRepository();
             return this._IRepository;
        }
    }

   // Add same for IBusinessRepository
}
于 2010-02-27T20:03:15.110 回答
0

您的存储库是否具有对象级状态?可能不会,所以将它们创建为单例并让 DI 容器将它们提供给 CACService。

否则,它们的创建成本真的很高吗?如果不是这样,与 RPC 和数据库操作相比,每个请求创建一个新的成本可以忽略不计。

使用Ninject依赖注入容器,您的 CACService 可能如下所示。其他 DI 容器也有同样简洁的机制来执行此操作。

public class CACSService
{
    public CACService
    {
        // need to do this since WCF creates us
        KernelContainer.Inject( this );
    }

    [Inject]
    public IUserRepository Repository
    { set; get; }

    [Inject]
    public IBusinessRepository BusinessRepository
    { set; get; }
}

在你的应用程序启动期间,你会告诉 Ninject 这些类型。

Bind<IUserRepository>().To<UserRepository>().InSingletonScope();
Bind<IBusinessRepository>().To<BusinessRepository>().InSingletonScope();
于 2010-02-27T20:29:41.327 回答
0

前言:这是依赖倒置的一般指南。如果您需要默认构造函数来完成这项工作(例如,如果它是通过反射或其他方式新建的),那么干净地执行此操作将更加困难。

如果您想让您的应用程序可配置,这意味着能够改变对象图的构造方式。用非常简单的术语来说,如果你想改变某个东西的实现(例如,有时你想要一个 的实例UserRepository,其他时候你想要一个 的实例MemoryUserRepository),那么使用该实现的类型(CACService在这种情况下)不应该负责更新它了。每次使用都会new将您绑定到特定的实现。 Misko 写了一些关于这一点的好文章

依赖倒置原则通常被称为“自上而下的参数化”,因为每个具体类型都从调用者那里接收其(已经实例化的)依赖。

要将其付诸实践,请将对象创建代码移出 的无CACService参数构造函数并将其放入工厂中。

然后,您可以根据以下内容选择以不同方式连接事物:

  • 读入配置文件
  • 将参数传递给工厂
  • 创建不同类型的工厂

将类型分为两类(创建事物的类型和执行事物的类型)是一种强大的技术。

例如,这是使用工厂接口的一种相对简单的方法——我们只需新建适合我们需要的工厂并调用它的Create方法。我们使用 Dependency Injection 容器 ( Autofac ) 在工作中执行此操作,但对于您的需求而言,这可能是多余的。

public interface ICACServiceFactory
{
    CACService Create();
}

// A factory responsible for creating a 'real' version
public class RemoteCACServiceFactory : ICACServiceFactory
{
    public CACService Create()
    {
         return new CACService(new UserRepository(), new BusinessRepository());
    }        
}

// Returns a service configuration for local runs & unit testing
public class LocalCACServiceFactory : ICACServiceFactory
{
    public CACService Create()
    {
         return new CACService(
               new MemoryUserRepository(), 
               new MemoryBusinessRepository());
    }     
}
于 2010-02-27T20:40:02.337 回答