Я начну здесь с небольшого фона. У нас есть веб-приложение 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 в представлениях), но мы не уверены, какой лучший способ определить, какую реализацию бизнес-службы использовать. Мы рассмотрели несколько вариантов:
- Базовый класс контроллера и создание наследников, зависящих от типа элемента, затем нечто подобное со службами приложения. Это похоже на слабое решение - в итоге мы бы написали несколько классов, которые ничего не добавляют в плане функциональности, кроме как выяснить, с каким типом элементов мы имеем дело.
- Передайте флаг на уровень сервиса и создайте реализацию сервиса на фабрике (то есть SampleBusinessServiceFactory, которая принимает аргумент "itemType" в своем методе CreateInstance). Проблема в том, что мы передаем переменную на несколько уровней, чтобы мы могли принять решение о реализации. Мы уже использовали этот подход.
- Generics - мы на самом деле не продумали этот вопрос, но, похоже, с этим тоже будут некоторые трудности (как бы вы вызвали метод Action с обобщениями из вызова ActionResult в представлении?). В некотором смысле это будет похоже на передачу флага вниз, но будет основано на строгой типизации объекта / служб вместо использования строк enums / magic.
Какой подход лучше всего подходит для решения этой проблемы? Новые варианты будут приветствоваться.
Любая предоставленная помощь будет высоко оценена.
Приветствия
Zac