2016-02-17 2 views
0

Я использовал TPH в Entity Framework для создания таблицы Inventory в моей базе данных.Дизайн шаблонов для разрешения зависимостей с использованием Autofac для Entity Framework Наследование TPH

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. Я уверен, что кто-то столкнулся бы с этим раньше. Благодаря!

ответ

1

Здесь вы можете использовать заводскую модель.

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. Этот метод класса обслуживания теперь можно тестировать на блоке, так как вы можете издеваться над фабрикой.

И сама фабрика является проверяемой единицей, так как вам просто нужно пройти в соответствующих экземплярах «инвентаря», чтобы утверждать правильные конкретные репозитории.

p.s. обратите внимание, что Autofac даже не нужен фабричный интерфейс/конкретный класс. он может вводить вам автоматические фабрики. Но это просто предпочтение людей использовать автоматические фабрики Autofac против явных основанных на интерфейсах фабрик. Какой бы вы предпочитаете.

Кроме того, GetType немного производительность интенсивный вызов .. в сценариях производства, если ваш метод AddItems называется несколько тысяч раз, GetType не хороший первый вариант .. много людей решить следующим образом:

  1. Добавить абстрактный геттер только перечисление под названием inventoryType к абстрактному Inventory классу

  2. имеет значение определения перечисления как CycleCount, SkuGroup и т.д.

  3. Override перечисления получить в конкретных классах детей с их конкретными типами.

  4. Как только это произойдет, метод CreateInventoryRepo может принимать это перечисление в качестве параметра.

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

я работал по той же схеме тоже .... рад узнать, что я на правильном пути. – Purusartha

+0

прохладный. хорошо знать, что вы были на том же пути. и просто nit .. назовите завод как IInventoryRepoFactory, так как он создает репо, а не инвентарь –