为对象工厂提供数据库上下文



当我在代码中使用工厂模式时,我总是问自己一个问题(C#,但它适用于我认为的任何语言)。

我有一个"服务",负责与我的数据库交互,与对象做一些事情并与我的对象模型进行交互。

此服务有时使用工厂来委派对象的实例化。 但是这个工厂显然需要自己与数据库交互才能正确地实例化我的对象。 例如,将数据库上下文传递给 Create 方法是一种好的做法还是坏的做法?

喜欢这个:

var myNewObject = MyFactory.Create(myDatabaseContext);

另一种方法是让服务始终是唯一数据库通信的服务。

var myNewObject = MyFactory.Create();
var extraProperty = myDatabaseContext.Get(something);
myNewObject.extraProp = extraProperty;

有什么建议吗?

将数据库上下文传递到工厂创建方法的想法称为方法注入。这是依赖注入的一种形式,因此您走在正确的轨道上。

可以使用依赖项注入通过构造函数管理工厂内的数据库上下文。工厂可能看起来像这样:

public class MyFactory 
{
private readonly IMyDbContext dbContext;
public MyFactory(IMyDbContext dbContext)
{
this.dbContext = dbContext;
}
public object Create()
{
// Use the dbContext, etc
}
}

构造函数注入通常受到青睐,因为它使方法签名不那么混乱。我们还很可能拥有一种类型的数据库上下文,因此无需利用基于其他一些运行时信息的多态性。

您可以选择使用依赖注入容器,如 Ninject 或我最喜欢的 SimpleInjector 来为您管理依赖关系。

只有工厂才能使用 DbContext。您可能需要注意的一件事是,工厂的用户可能没有意识到工厂正在调用数据库。这可能是一件坏事,并且会对性能产生负面影响。通常,构造信息传递到工厂方法中,而不是从数据库初始化到工厂方法中。您甚至可以更进一步,使用存储库模式来抽象出更多的数据访问逻辑,如果您认为这是必要的,并且您还没有这样做。

要了解有关依赖注入的更多信息,如果您不熟悉,可以从这里开始。

我的理想结构可能如下所示:

public class MyFactory : IFactory
{  
public object Create(object someProperty)
{
// build object
}
}
public class MyService
{
private readonly IMyDbContext dbContext;
private readonly IFactory factory;
public MyService(IMyDbContext dbContext, IFactory factory)
{
this.dbContext = dbContext;
this.factory = factory;
}
public void DoWork()
{
var property = dbContext.Get(something);
var newObj = factory.Create(property);
// Use stuff
}
}

在我正在从事的项目中,我们尝试将所有数据库访问权限保留在服务中。如果工厂需要必须从数据库加载的对象,则服务应加载它们并将其传递给工厂。如果工厂返回的对象应持久化,则服务应将其添加到 DbContext。

这对应于您展示的第二种方式。优点是工厂可以进行单元测试,而无需模拟 DbContext。

如果你想在工厂内保留数据库访问权限,我会将 DbContext 注入工厂的构造函数中,而不是将其传递给 Create() 方法。

服务依次获取注入的工厂实例(而不是访问工厂的静态方法)。同样,这将使嘲笑变得更加容易。

public class Service {
private readonly IMyDbContext _myDatabaseContext;
private readonly IMyFactory _myfactory;
public Service (IMyDbContext myDbContext, IMyFactory myfactory) {
_myDatabaseContext = myDbContext;
_myfactory = myfactory
}
public void Create() {
var extraProperty = myDatabaseContext.Get(something);
var myNewObject = _myFactory.Create(extraProperty);
_myDatabaseContext.Add(myNewObject);
_myDatabaseContext.SaveChanges();
}
}

最新更新