Как открыть доступ к внутреннему домену только для репозиториев - PullRequest
0 голосов
/ 18 июня 2019

Рассмотрим эту упрощенную модель:

a Класс подписки:

public class Subscription
{
    public string Name { get; }
    public ReadOnlyCollection<Subscriber> Subscribers => _subscribers.AsReadOnly();

    private readonly List<Subscriber> _subscribers;

    public Subscription(string name)
    {
        Name = name;
        _subscribers = new List<Subscriber>();
    }

    public Subscriber AddRecipient(Recipient recipient, ReceivingMethod receivingMethod)
    {
        var subscriber = new Subscriber(this, receivingMethod, recipient);
        _subscribers.Add(subscriber);
        return subscriber;
    }

    internal bool RemoveSubscriber(Subscriber subscriber)
        => _subscribers.Contains(subscriber) && _subscribers.Remove(subscriber);
}

a Класс получателя:

public class Recipient
{
    public Guid Id { get; }
    public string Address { get; set; }

    public Recipient(string address) : this(Guid.NewGuid(), address)
    {
    }

    internal Recipient(Guid id, string address)
    {
        Id = id;
        Address = address;
    }

    public Subscriber Subscribe(Subscription subscription, ReceivingMethod receivingMethod) 
        => subscription.AddRecipient(this, receivingMethod);
}

и подписчик

public class Subscriber : Recipient
{
    public Subscription Subscription { get; set; }
    public ReceivingMethod ReceivingMethod { get; set; }

    internal Subscriber(Subscription subscription, ReceivingMethod method, Recipient recipient)
        : base(recipient.Id, recipient.Address)
    {
        Subscription = subscription;
        ReceivingMethod = method;
    }

    public bool Unsubscribe() 
        => Subscription != null && Subscription.RemoveSubscriber(this);
}

A Subscriber приводит к тому, что Recipient подписывается на Subscription и, как таковое, экземпляр этого объекта внутренне запрещен.На данный момент мне нужно загрузить и заполнить существующие Subscriber s из репозитория, реализация которого находится в другом пространстве имен (.Infrastructure) и не может получить доступ к внутренним элементам домена из-за его уровня защиты.

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

Может кто-нибудь объяснить, как это обычно делается в модели с расширенным доменом.

PS: Это архитектурный вопрос на уровне приложений, и поэтому я думаю, что он лучше всего подходит для SO.

Ответы [ 3 ]

2 голосов
/ 18 июня 2019

Как сказал @maxdoxdev: вероятно, нет ничего плохого в том, чтобы иметь классы домена с открытым конструктором.

Если вы чувствуете, что определенно не хотите общедоступных конструкторов, тогда вы можете выбрать публичный метод фабрики для соответствующего класса или использовать примитивы в ваших Add методах для методаСам для внутреннего создания требуемого объекта (ов).

1 голос
/ 18 июня 2019

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

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

Архитектура лука допускает зависимость от внутренней части лука (то есть по направлению к домену).

Пожалуйста, обратитесь к этому изображению: https://www.codeguru.com/imagesvr_ce/2236/Onion1.png

или к полной статье: https://www.codeguru.com/csharp/csharp/cs_misc/designtechniques/understanding-onion-architecture.html

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

РЕДАКТИРОВАТЬ:

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

Приложение содержит интерфейсы репозиториев, инфраструктур и других внешних зависимостей.Эти интерфейсы реализованы на разных уровнях и в целом внедряются на уровне персистентности (UI) с помощью IoC.

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

Пример:

Контроллер - принимает DTO и сопоставляет его с Query или Command

Приложение - обрабатывает Query или Command путем вызоваабстракции от внешних уровней и реальные реализации домена

домен - имеет богатые модели, которые знают, как выполнять бизнес-действия

хранилища - просто реализации доступа к данным

Взгляните наэтот GitHub: https://github.com/matthewrenze/clean-architecture-demo Это также связано с отличным видео Pluralsight, если вы заинтересованы.

0 голосов
/ 18 июня 2019

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

Поскольку Subscriber является продуктом Recipient, подписавшимся на конкретный Subscription, который здесь является совокупным корнем , и поэтому изначально отвечает за создание Subscriber, которое он до сих пор, но кроме того, я сделал общедоступным конструктор Subscriber, чтобы разрешить добавление загруженных сущностей.

Сделав конструктор Subscriber публичным, я познакомился с проблемой, чтобы убедиться, что новый Subscriber находится в действительном состоянии. Под этим я подразумеваю, что также Subscriber указывает на Subscription, поскольку Subscription также содержит Subscriber в своей коллекции Подписчиков и другие зависимости, которые до этого обрабатывались Subscription создание. Решение в конце кажется довольно простым (в конце) и состоит в добавлении внутреннего метода для добавления Subscriber к *1023* Подписчикам и применения других правил, которые ранее были только доступно "подпиской" на Recipient.

Итак, я обогатил Subscription класс:

internal void AddSubscriber(Subscriber subscriber)
{
    if (_subscribers.Contains(subscriber)) return;

    _subscribers.Add(subscriber);
    subscriber.Subscription = this;
}

И изменил конструктор Subscriber:

public Subscriber(Subscription subscription, ReceivingMethod receivingMethod, Recipient recipient)
    : base(recipient.EMailAdress, recipient.FirstName, recipient.LastName, recipient.Salutation)
{
    Subscription = subscription;
    ReceivingMethod = receivingMethod;
    subscription.AddSubscriber(this);
}

Теперь репозиторий может создавать Subscribers из загруженной модели персистентности.

Я все еще открыт для лучшего подхода и / или подробностей о недостатках этого подхода.

...