Мы часто используем простые перечисления для представления состояния наших сущностей. Проблема возникает, когда мы вводим поведение, которое в значительной степени зависит от состояния или когда переходы между состояниями должны соответствовать определенным бизнес-правилам.
Возьмем следующий пример (, в котором для представления состояния используется перечисление.):
public class Vacancy {
private VacancyState currentState;
public void Approve() {
if (CanBeApproved()) {
currentState.Approve();
}
}
public bool CanBeApproved() {
return currentState == VacancyState.Unapproved
|| currentState == VacancyState.Removed
}
private enum VacancyState {
Unapproved,
Approved,
Rejected,
Completed,
Removed
}
}
Вы можете видеть, что этот класс скоро станет довольно многословным, поскольку мы добавим методы для Reject, Complete, Remove и т. д.
Вместо этого мы можем ввести шаблон состояния, который позволяет нам инкапсулировать каждое состояние как объект :
public abstract class VacancyState {
protected Vacancy vacancy;
public VacancyState(Vacancy vacancy) {
this.vacancy = vacancy;
}
public abstract void Approve();
// public abstract void Unapprove();
// public abstract void Reject();
// etc.
public virtual bool CanApprove() {
return false;
}
}
public abstract class UnapprovedState : VacancyState {
public UnapprovedState(vacancy) : base(vacancy) { }
public override void Approve() {
vacancy.State = new ApprovedState(vacancy);
}
public override bool CanApprove() {
return true;
}
}
. Это упрощает переход между состояниями, выполнение логики на основе текущего состояния или добавление новых состояний, если нам нужно:
// transition state
vacancy.State.Approve();
// conditional
model.ShowRejectButton = vacancy.State.CanReject();
Эта инкапсуляция кажется более чистой, но с учетом достаточно состояний, они тоже могут стать очень многословными. Я читал сообщение Грега Янга о неправильном использовании паттерна состояний , в котором предлагается использовать полиморфизм вместо (, поэтому я бы использовал классы ApprovedVacancy, UnapprovedVacancy и т. д.), но не вижу, как это мне поможет.
Должен ли я делегировать такие переходы между состояниями доменной службе или правильно ли я использую шаблон состояния в этой ситуации?