我们经常使用简单的枚举来表示实体的状态。当我们引入很大程度上取决于状态的行为时,问题就出现了,或者状态转换必须遵守某些业务规则。
举个例子(使用枚举来表示状态):
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();
这种封装看起来更简洁,但给定足够多的状态,这些也可能变得非常冗长。我读了Greg Young 关于状态模式滥用的帖子,它建议改用多态性(所以我会有 ApprovedVacancy、UnapprovedVacancy 等类),但看不出这对我有什么帮助。
我应该将这种状态转换委托给域服务,还是在这种情况下我使用状态模式是否正确?