设计模式以使用实体框架 TPH 继承的 Autofac 解析依赖关系

本文关键字:Autofac 关系 依赖 继承 TPH 实体 框架 设计模式 | 更新日期: 2023-09-27 18:35:00

我在实体框架中使用TPH在我的数据库中创建了Inventory表。

public abstract class Inventory
{
    public Guid Id { get; set; }
    public DateTime On { get; set; }
}
public class CycleCountInventory : Inventory
{
    public string Frequency { get; set; }
    // and other properties
}
public class SkuGroupInventory : Inventory
{
    public string SkuGroup { get; set; }
    // and other properties
}

我有一个要求,可以将物品添加到库存中。但是,库存存储库的行为应因库存类型而异。我有一个服务类,其中包含对存储库的引用,如下所示:

public class InventoryService : IInventoryService
{
    public bool AddItems(Inventory inventory, IList<Guid> itemsGuidList)
    {
        // the inventory type is only known at this point
        IInventoryRepo repo = (inventory is SkuGroupInventory)
            ? (IInventoryRepo) new SkuGroupInventoryRepo()
            : new CycleCountInventoryRepo();
        return repo.PerformInventory(itemsGuidList);
    }
}

目前,我正在通过手动进行检查来加载IInventoryRepo的不同实现。这种方法存在一些问题:
1.我使用Autofac来解决所有依赖项...这种方法使我的代码难以测试
2. 随着更多类型的库存添加,我的代码将变得难以管理

是否有任何模式(抽象工厂/策略等(可用于将依赖项的解析委托回 Autofac。我相信以前有人会面对这种情况。谢谢!

设计模式以使用实体框架 TPH 继承的 Autofac 解析依赖关系

您可以在此处使用工厂模式。

public interface IInventoryFactory 
{
 // instead of type, you could also have a discriminator on the
 // inventory class, to give its specific type. (enum etc.)
 IInventoryRepo CreateInventoryRepo(Type inventoryType);
}
public class MyInventoryFactory : IInventoryFactory 
{
 // instead of type, you could also have a discriminator on the
 // inventory class, to give its specific type. (enum etc.)
 public IInventoryRepo CreateInventoryRepo(Type inventoryType)
 {
   IInventoryRepo repo = (inventoryType == typeof(SkuGroupInventory))
        ? (IInventoryRepo) new SkuGroupInventoryRepo()
        : new CycleCountInventoryRepo();
   return repo;
 }
}
public class InventoryService : IInventoryService
{
    private readonly IInventoryFactory _inventoryFactory;
    public InventoryService(IInventoryFactory inventoryFactory)
    {
     _inventoryFactory = inventoryFactory;
    }
    public bool AddItems(Inventory inventory, IList<Guid> itemsGuidList)
    {
        // create the right repo based on type of inventory.
        // defer it to the factory
        IInventoryRepo repo = _inventoryFactory.CreateInventoryRepo(inventory.GetType());
        return repo.PerformInventory(itemsGuidList);
    }
 }

工厂的真正具体实现将由Autofac注入,因此请在Autofac中注册。此服务类方法现在是单元可测试的,因为您可以模拟工厂。

工厂本身是可单元测试的,因为您只需要传入适当的"库存"实例即可断言正确的具体存储库。

附言请注意,Autofac甚至不需要工厂接口/混凝土类。 它可以为您注入自动工厂。但这只是人们的偏好,即使用 Autofac 自动工厂而不是基于显式接口的工厂。无论您喜欢哪个。

此外,GetType 是稍微占用性能的调用......在生产场景中,如果你的 AddItems 方法被调用了几千次,那么 GetType 不是一个好的 FIRST 选项......很多人按如下方式解决它:

  1. 将一个名为 inventoryType 的抽象 getter 枚举添加到抽象库存类

  2. 将枚举定义值作为 CycleCount、SkuGroup 等。

  3. 使用特定类型覆盖具体子类中的枚举 getter。

  4. 一旦发生这种情况,CreateInventoryRepo 方法就可以将此枚举作为参数。

public IInventoryRepo CreateInventoryRepo(InventoryType inventoryType)  
{    
 IInventoryRepo repo = (inventoryType == InventoryType.SkuGroup)
                       ? (IInventoryRepo) new SkuGroupInventoryRepo()
                       : new CycleCountInventoryRepo();
 return repo;  
}