Исследование ядра
Доменная модель – самая важная часть приложения. Без доменной модели все соответствующие понятия были бы представлены только в пользовательском интерфейсе. Наша конкретная доменная модель содержит единичный агрегат, состоящий из единичного объекта, Visitor
.
Ниже представлен код класса Visitor
.
Листинг 15-1: Класс Visitor
, доменная модель данного примера
using System;
namespace Core
{
public class Visitor
{
public Guid Id { get; set; }
public string PathAndQuerystring { get; set; }
public string LoginName { get; set; }
public string Browser { get; set; }
public DateTime VisitDate { get; set; }
public string IpAddress { get; set; }
}
}
Здесь отсутствует бизнес-логика, и с первого взгляда, это похоже всего лишь на структуру данных. Все остальные моменты пропущены с целью включения только абстракций и логики, которые необходимы для продвижения NHibernate свободным способом.
Класс Visitor
содержит свойства для каждого вида информации, которую нам хотелось бы записать. Свойство Id
существует в качестве идентификатора конкретного посещения. Мы точно могли бы использовать Int32
в качестве ID
, но в среде хранения данных, которая вынуждает использовать зависимость от хранилища данных при генерации уникального значения Int32
. Иногда это приемлимо, но в DDD разработчик допускает ошибку в том плане, что отдает всю ответственность доменной модели, а не хранилищу данных. В соответствии с этим Id
– это Guid
, и приложение будет генерировать Guid
перед тем, как попытаться выполнить сохранение в базу данных.
Механизм сохранения или извлечения Visitor
называется репозиторием. Репозиторий будет сохранять наш объект, а также извлекать его. Он также может исполнять операции фильтрации. В нашей доменной модели есть IVisitorRepository
:
Листинг 15-2: Репозиторий, который определяет операции сохранения
namespace Core
{
public interface IVisitorRepository
{
void Save(Visitor visitor);
Visitor[] GetRecentVisitors(int numberOfVisitors);
}
}
С помощью нашего репозитория мы можем сохранить Visitor
, а также получить конкретное количество самых последних посетителей. На рисунке 15-4 вы можете видеть, что проект Core не содержит ни одного класса, реализующего IVisitorRepository
. Это важно, поскольку класс, который выполняет работу, представленную интерфейсом, будет ответственным за сохранение, что не является заботой доменной модели. Сохранение – это инфраструктура. Данная функциональность работала бы одинаково хорошо, если бы мы сохраняли данные в файл, а не в базу данных. Механизм сохранения не входит в компетенции доменной модели, поэтому и класс, ответственный за него, отсутствует в проекте Core.
То, что находится в проекте Core, – это абстрактная фабрика, способная размещать или создавать экземпляры IVisitorRepository
. VisitorRepositoryFactory
отвечает за возврат экземпляра нашего репозитория. Следующий листинг иллюстрирует тот факт, что знания, необходимые для создания репозитория, не расположены в рамках фабрики. Эта фабрика просто олицетворяет способность возврата репозитория.
Листинг 15-3: Фабрика, которая предоставляет репозиторий
using System;
namespace Core
{
public class VisitorRepositoryFactory
{
public static Func<IVisitorRepository> RepositoryBuilder =
CreateDefaultRepositoryBuilder;
private static IVisitorRepository CreateDefaultRepositoryBuilder()
{
throw new Exception("No repository builder specified.");
}
public IVisitorRepository BuildRepository()
{
IVisitorRepository repository = RepositoryBuilder();
return repository;
}
}
}
Строка 6-7: Инициализируется при запуске приложения
Строка 11: Выдается в случае, если фабрика не проинициализирована
Строка 16: Использует делегирование для создания репозитория
Даже для неопытного глаза этот класс кажется не столь полезным в одиночку. При вызове BuildFactory()
выдается исключение. Доменная модель не знает, какая реализация IVisitorRepository
будет использоваться, поэтому нет способа вложить это знание в скомпилированный код. В свойстве public static RepositoryBuilder
необходимо будет задать что-то полезное перед тем, как фабрика заработает должным образом. Мы рассмотрим то, как это выполняется после того, как ознакомимся со всем необходимым.
Данная конкретная фабрика не нужна, если вы используете IoC-контейнер, который был пропущен для простоты. Эта доменная модель умышленно является простой.
Следующий шаг – понять, как настроить NHibernate для автоматического сохранения нашего объекта в базу данных.