Мы с коллегами собираем небольшую структуру отчетности для интернет-магазина. Мы создали библиотеку по образцу репозитория, используя «отчеты» в качестве репозиториев и очень легкий сервисный уровень для взаимодействия с указанными отчетами. Наш код отлично работает и довольно прост в использовании. Однако есть одна вещь, которая беспокоит меня лично: на уровне фабрики сервисов нам нужно дважды объявлять наш возвращаемый тип (это не выводится). Вот основа нашего проекта:
Интерфейс отчета
Это то, что используется в качестве наших «Репозиториев». Они принимают объекты доступа к данным, такие как классы-оболочки для соединения SQL/Oracle или API нашего магазина.
internal interface IReport<T>
{
T GetReportData(dynamic options);
}
Фабрика репозиториев
Это обеспечивает простой способ создания таких отчетов, зная их тип.
internal interface IReportFactory
{
TR GenerateNewReport<T, TR>() where TR : IReport<T>;
}
internal class ReportFactory : IReportFactory
{
public ReportFactory()
{
// some initialization stuff
}
public TR GenerateNewReport<T, TR>() where TR : IReport<T>
{
try
{
return (TR)Activator.CreateInstance(typeof(TR));
}
catch(Exception ex)
{
// Logging
}
}
}
Пример отчета (репозиторий)
Вот как должен выглядеть отчет. Обратите внимание, что он возвращает DataTable и объявляется с ним в универсальном интерфейсе (это скоро появится).
internal class ItemReport : IReport<DataTable>
{
public DataTable GetReportData(dynamic options)
{
return new DataTable();
}
}
Служба отчетов
Облегченный сервис, который принимает отчет (репозиторий) и работает с ним. Легкий, но он позволяет легко проводить модульное тестирование и тому подобное, и если мы когда-нибудь захотим добавить дополнительную обработку после извлечения отчетов, это будет легко сделать.
public interface IReportService<T>
{
T GetReportData(dynamic options);
}
public class ReportService<T> : IReportService<T>
{
private readonly IReport<T> _report;
public ReportService(IReport<T> report)
{
_report = report;
}
public T GetReportData(dynamic options)
{
return _report.GetReportData(options);
}
}
Фабрика услуг
У нас есть фабрика сервисов, настроенная как абстрактный класс (поскольку все фабрики сервисов должны будут создать фабрику отчетов), заставляя конструктор по умолчанию:
public abstract class ReportServiceFactory
{
protected IReportFactory ReportFactory;
protected ReportServiceFactory(connection strings and other stuff)
{
ReportFactory = new ReportFactory(connection strings and other stuff);
}
}
Затем мы можем создать отдельные сервисные фабрики на основе функций. Например, у нас есть фабрика услуг «стандартный отчет», а также фабрики услуг для конкретных клиентов. Реализация здесь, где мой вопрос.
public class SpecificUserServiceFactory : ReportServiceFactory
{
public SpecificUserServiceFactory(connection strings and other stuff) : base(connection strings and other stuff){}
public IReport<DataTable> GetItemReport()
{
return new ReportService<DataTable>(ReportFactory.GenerateNewReport<DataTable, ItemReport>());
}
}
Почему я должен быть таким многословным при создании фабрики услуг? Я объявляю возвращаемый тип дважды. Почему я не могу сделать что-то вроде этого:
return new ReportService(ReportFactory.GenerateNewReport<ItemReport>());
Обратите внимание, что здесь я не объявляю DataTable; Я думаю, что это следует сделать из того факта, что ItemReport — это IReport. Буду очень признателен за любые предложения о том, как заставить его работать таким образом.
Извините за такое длинное объяснение такого простого вопроса, но я подумал, что весь этот резервный код поможет найти решение. Еще раз спасибо!
IReportFactory
выглядит подозрительно. - person leppie   schedule 13.11.2011