Выбор экземпляров интерфейса на основе определенного значения

Я начну здесь с небольшой предыстории. У нас есть веб-приложение ASP.Net MVC, которое базируется на структуре, примерно основанной на Onion Architecture ] Таким образом, мы имеем следующую (упрощенную) вертикальную структуру:

  • ASP. Уровень контроллера Net MVC
  • Уровень прикладных сервисов
  • Уровень бизнес-сервисов

ПРИМЕЧАНИЕ. Вышеупомянутое упрощено, потому что оно не касается представлений, репозиториев, объектов домена и т. Д., Которые не имеют отношения к этому вопросу.

Для горизонтальной структуры у нас есть некоторые основные области, определяемые тем, что мы называем «Типами элементов» (для простоты этот вопрос будет касаться двух типов элементов: «ItemTypeA», «ItemTypeB» и т. Д.).

У нас есть интерфейс бизнес-службы, который имеет отдельную реализацию для каждого типа элемента:

public interface ISampleBusinessService
{
    string SampleMethod(string arg);
}

public class ItemTypeASampleBusinessService : ISampleBusinessService
{
    public string SampleMethod(string arg)
    {
        return "Item Type A: " + arg;
    }
}

public class ItemTypeBSampleBusinessService : ISampleBusinessService
{
    public string SampleMethod(string arg)
    {
        return "Item Type B: " + arg;
    }
}

Выше - служба приложения, которая использует бизнес-службу:

public interface ISampleAppService
{
    string SampleMethod(string arg);
}

public class SampleAppService
{
    private readonly ISampleBusinessService service;

    public SampleAppService(ISampleBusinessService service)
    {
        this.service = service
    }

    public string SampleMethod(string arg)
    {
        return service.SampleMethod(arg);
    }
}

А сверху - наш контроллер, который использует службу приложения:

public class SampleController : Controller
{
    private ISampelAppService service

    public SampleController(ISampleAppService service)
    {
        this.service = service;
    }

    public PartialViewResult SampleAction(string arg)
    {
        return PartialView( service.SampleMethod(arg) );
    }
}

Обратите внимание, что контроллер, интерфейс и реализация службы приложения, и интерфейс бизнес-службы являются общими - им не важно, какой тип элемента используется. Однако реализации бизнес-службы зависят от типа элемента. Мы знаем, с каким типом элементов имеем дело, когда вызываем метод действия на контроллере (через RenderAction в представлениях), но мы не уверены, какой лучший способ определить, какую реализацию бизнес-службы использовать. Мы рассмотрели несколько вариантов:

  1. Базовый класс контроллера и создание наследников контроллера, зависящих от типа элемента, а затем нечто подобное со службами приложений. Это кажется слабым решением - мы бы в конечном итоге написали несколько классов, которые ничего не добавляют с точки зрения функциональности, кроме определения того, с каким типом элементов мы имеем дело.
  2. Передайте флаг на уровень сервиса и создайте реализацию сервиса в фабрике (т. Е. SampleBusinessServiceFactory, который принимает аргумент «itemType» в своем методе CreateInstance). Проблема в том, что мы передаем переменную на несколько уровней, чтобы мы могли принять решение о реализации. Мы использовали этот подход до сих пор.
  3. Generics - мы действительно не продумали этот вариант, но похоже, что с этим также возникнут некоторые трудности (как бы вы могли вызвать метод Action с универсальными шаблонами из вызова ActionResult в вид?). В некотором смысле это было бы похоже на передачу флага, но основывалось бы на строго типизированных объектах / службах вместо использования перечислений / магических строк.

Какой подход лучше всего подходит для решения этой проблемы? Приветствуются новые варианты. Zac

1
задан Zac Seth 11 October 2010 в 21:02
поделиться