【问题标题】:Giving database context to object Factory为对象工厂提供数据库上下文
【发布时间】:2017-03-30 14:00:06
【问题描述】:

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

我有一个“服务”,负责与我的数据库交互、处理对象并与我的对象模型交互。

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

像这样:

var myNewObject = MyFactory.Create(myDatabaseContext);

另一种方法是让服务始终唯一与数据库对话。

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

有什么建议吗?

【问题讨论】:

  • 使用 DI 容器来创建上下文,不要让它成为工厂的工作或数据库的任何其他用户的工作

标签: c# entity-framework design-patterns dbcontext factory-pattern


【解决方案1】:

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

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

public class MyFactory 
{
    private readonly IMyDbContext dbContext;

    public MyFactory(IMyDbContext dbContext)
    {
        this.dbContext = dbContext;
    }

    public object Create()
    {
        // Use the dbContext, etc
    }
}

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

您可以选择使用像 Ninject 或我最喜欢的 SimpleInjector 这样的依赖注入容器来为您管理依赖项。

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

要了解更多关于依赖注入的信息,如果你不熟悉,you can start here

我的理想结构可能是这样的:

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
    }
}

【讨论】:

  • 正是我最终所做的。我也使用 SimpleInjector,这是我用过的最好的 DI 容器 :) 另外,将工厂用作单例或每次需要时实例化的标准对象有什么好处吗?由于我的工厂继承自 AbstractFactory,因此无论如何我都无法使其成为静态的。但我想我可以把它变成一个单例。
  • 我认为您在保留工厂和实例方面会有更多好处。它将允许您在测试中轻松地模拟它,并在需要时快速更改实现。如果工厂是无状态的,没有依赖关系,并且易于测试,因为它可能没有理由不能是静态的。
  • 它不能是静态的唯一原因是因为“静态类必须从对象派生”。由于 AbstractFactory 是抽象的,因此无法实例化......好吧,我想你明白我的意思了 ;)
  • 对,您需要删除该继承以使其成为静态。
【解决方案2】:

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

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

如果您无论如何都想在 Factory 中保留 DB 访问权限,我会将 DbContext 注入到 Factory 的构造函数中,而不是将其传递给 Create() 方法。

Service 依次获取注入的 Factory 实例(而不是访问 Factory 的静态方法)。同样,这将使模拟变得更加容易。

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();
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-03-03
    • 1970-01-01
    • 1970-01-01
    • 2014-03-29
    • 2014-02-10
    • 2020-04-02
    • 1970-01-01
    • 2022-01-07
    相关资源
    最近更新 更多