Упростить переход состояния класса сущности DDD - PullRequest
0 голосов
/ 09 сентября 2018

Я впервые пытаюсь разработать приложение DDD.

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

protected static readonly IDictionary<State, State[]> aGoodName = new Dictionary<State, State[]>
{
    { State.Approved, new State[] { State.Requested } },
    { State.Standardized, new State[] { State.Approved } },
    { State.Queued, new State[] { State.Standardized, State.Succeeded, State.Failed } },
    { State.Running, new State[] { State.Queued } },
    { State.Succeeded, new State[] { State.Running } },
    { State.Failed, new State[] { State.Running } },
    { State.Completed, new State[] { State.Succeeded } },
    { State.Canceled, new State[] { State.Requested, State.Approved, State.Standardized, State.Succeeded, State.Failed, State.Queued } }
};

У меня есть один универсальный метод, который имеет желаемое состояние в качестве параметра и проверяет, можно ли переходить из него:

public void Transition(State state)
{
    if (!aGoodName[state].Contains(State))
    {
        throw new ArgumentException($"Cannot change state from {State.ToString()} to {state.ToString()}.");
    }

    State = state;
}

Однако, если я правильно понимаю, способ DDD состоит в том, чтобы выразить код домена на языке, который понятен как разработчикам, так и деловым людям, поэтому, например, было бы более разумно иметь метод, скажем, для преемственности:

public void Succeed()
{
    Transition(State.Succeeded);
}

Или даже:

public void Succeed()
{
    var states = new List<State> { State.Running };

    if (!states.Contains(State))
    {
        throw new ArgumentException($"Cannot change state from {State.ToString()} to {State.Succeeded.ToString()}.");
    }

    State = State.Succeeded;
}

Я довольно новичок в этом шаблоне проектирования и хотел бы знать, какой из вышеуказанных подходов наиболее подходит для DDD.

1 Ответ

0 голосов
/ 09 сентября 2018

Я думаю, что ответ на ваш вопрос в первую очередь зависит от другого вопроса:

  • Насколько эти состояния важны в вашем домене?

Что важно здесь, так это рассмотреть литературу предметной области (иначе говоря, Ubiquitous Language) в дизайне. Но детали реализации на самом деле зависят от важности проблемы. Это могут быть даже независимые лица!

entity.To(new ApprovedState());

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

interface IState{...}

class Approved : IState {...}

class Requested : IState {...}

class Entity{
   public IState State {get; set;}
}

Наконец, вы можете предоставить тонкий слой свободного API для более тонкого выражения вашего домена (конечно, вы можете разработать его и таким образом ...):

TheEntity.IfItsPossible().Approve();

Обновление

Здесь есть еще одна вещь. Иногда мы добавляем поля к нашим объектам так же, как мы делаем то же самое с таблицами в базах данных. Вот как все работает в мире БД! Но я думаю, что это совсем другое в DDD. Может быть, эти разные государства на самом деле играют роль разных сущностей или скрытых бизнес-правил, которые нужно копать глубже. Предположим, что Request не является состоянием перезагрузки, но это сама сущность, которую люди создают, когда им нужна перезагрузка. Так же, как при создании заказа, когда вам нужно купить продукт.

public class Reload
{
}

public class Request
{
    public string User { get; set; }
    public DateTime Time { get; set; }
    // and other logics about requests
}

public interface IFactory
{
    Reload Create(Request request);
}

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

public interface IQueueService
{
    void Push(Reload reload);
}


public IEnumerable<Reload> GetStandardizedReloads()
{
    return _queueService.Items();  
}

public IEnumerable<Request> GetRequests()
{
    return _requestRepository.GetAll();
}
...