DDD создает AggregateRoot Entity из внешнего API, репозиториев и доменных служб - PullRequest
0 голосов
/ 15 февраля 2019

Попытка применить принципы DDD к небольшому проекту ... У меня есть PlayerProfile совокупный корень, который состоит из Club сущности и коллекции Rating объектов значений.Периодически мне приходится синхронизировать все сущности PlayerProfile с внешнего портала, анализируя необработанный HTML.

А сейчас я придумаю решение обернуть код, который обновляет PlayerProfile в простойPlayerProfileRepository, что-то вроде этого:

public interface IPlayerProfileRepository
{
    Task<IReadOnlyCollection<PlayerProfile>> SyncPlayersProfilesFromPortal(string sourceUrl);
    // other methods, which works with data storage
}

Во-первых, мне не очень нравится идея метода смешивания, который работает с хранилищем данных с методами, которые работают с внешним ресурсом (HTML-страницами) дляпериодически создавать PlayerProfile.Для меня это больше похоже на PlayerProfileFactory обязанности?

Фактическая реализация IPlayerProfileRepository делегирует парсинг фактических страниц 3 IPageParser, который фактически находится в том же слое, что и мои репозитории.Примерно так:

    public PlayerProfileRepository(
        IPageParser<ParseClubDto> clubPageParser,
        IPageParser<ParsePlayerProfileDto> playerProfilePageParser,
        IPageParser<ParseRatingDto> ratingPageParser)

    {
        _playerProfilePageParser = playerProfilePageParser;
        _clubPageParser = clubPageParser;
    }

Я не совсем уверен, что все эти Dtos на самом деле Dtos, как только они используются только с IPageParser для сохранения промежуточных данных при анализестраницы.Я хотел бы сохранить их близко к IPageParser реализациям на уровне службы данных, но не делить их в отдельном проекте Dtos и, возможно, назвать по-другому.

После ParseClubDto, ParsePlayerProfileDto и ParseRatingDto, проанализированныхЯ передал его фабричному методу PlayerProfileFactory.Create, что-то вроде этого:

var playerProfiles = new List<PlayerProfile>();

var clubs = await _clubPageParser.ParseAsync(sourceUrl);

foreach (var club in clubs)
{
    var clubPlayers = await _playerProfilePageParser.ParseAsync(club.PlayersPageUrl);

    foreach (var clubPlayer in clubPlayers)
    {
        var ratings = await _ratingPageParser.ParseAsync(clubPlayer.RatingsPageUrl);

        playerProfiles.Add(PlayerProfileFactory.Create(club, clubPlayer, ratings));
     }
}

return playerProfiles;

После того, как это сделано, я должен выполнить фактическую синхронизацию с существующими корнями агрегирования в БД, что я делаю просто, вызывая ResyncFrom(PlayerProfile profile)в совокупном корне или это больше похоже на отдельную PlayerProfile службу домена?

В общем, у меня возникло ощущение, что я делаю что-то не так, поэтому, пожалуйста, любые комментарии приветствуются?

Ответы [ 2 ]

0 голосов
/ 03 марта 2019

Интерфейс IPlayerProfileRepository обычно определяется в Домене и описывает внешнему миру, как должен быть получен Совокупный корень, обычно по Id.Таким образом, метод SyncPlayersProfilesFromPortal определенно не должен быть частью этого интерфейса.Синхронизация данных является проблемой инфраструктуры и может выполняться асинхронно в фоновом режиме, как уже предлагалось в предыдущем ответе.

0 голосов
/ 17 февраля 2019

Я думаю, что ваш пример - это случай интеграции двух BC с использованием шаблона уровня защиты от коррупции.

У меня был бы порт (интерфейс в домене) с контрактом метода, который возвращает список игроков.агрегаты профиля.

На уровне инфраструктуры у меня был бы адаптер, который реализует порт, считывая html-данные с удаленного портала (например, используя REST API) и создавая агрегаты из этих данных.

На прикладном уровне у меня была бы прикладная служба, в которой вы вводите и порт, и репозиторий совокупности профилей игроков, который работает с локальной базой данных.Служба приложений вызывает порт для создания агрегатов, а затем вызывает хранилище для их хранения.

Я периодически запускаю эту службу приложений.

Это будет асинхронная интеграция без событий, ноВы можете реализовать его с помощью событий, если удаленный портал запускает события.

...