我有一个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()
根据调用服务的代码或在为我的实体框架设计存储库时需要进行的任何其他建议,告诉它哪个存储库是新的。 Thankx
答案 0 :(得分: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。
这种方法的优点在于,在您需要之前不必执行此操作。通常情况下,这实际上并不是必需的,因此能够将这些优化推迟到实际需要之前是很好的。
答案 1 :(得分:0)
不是在构造中实例化(“newing up”)存储库,而是可以在它们的属性中延迟加载它们。这将允许您保留第二个构造函数,但让第一个构造函数不执行任何操作。
然后,用户可以根据需要分配这些内容。
例如:
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
}
答案 2 :(得分: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();
答案 3 :(得分:0)
前言:这是依赖倒置的一般指南。如果你需要默认的构造函数来完成工作(例如,如果它是通过反射或其他东西新建的话),那么干净地完成它将会更难。
如果要使应用程序可配置,则意味着能够改变对象图的构造方式。用非常简单的术语来说,如果你想改变某些事物的实现(例如,有时你想要一个UserRepository
的实例,有时你想要一个MemoryUserRepository
的实例),那么使用的类型实施(在这种情况下为CACService
)不应该用新功能来收费。 new
的每次使用都会将您绑定到特定的实现。 Misko has written some nice articles about this point
依赖性倒置原则通常被称为“来自上面的参数化”,因为每个具体类型从调用者接收其(已经实例化的)依赖性。
要将其付诸实践,请将对象创建代码移出CACService
的无参数构造函数,并将其放入工厂中。
然后,您可以根据以下内容选择不同的方式:
将类型分为两类(创建类型做事物的类型)是一种强大的技术。
E.g。这是使用工厂界面执行此操作的一种相对简单的方法 - 我们只是根据我们的需要新建任何工厂并调用其Create
方法。我们使用依赖注入容器(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());
}
}