我們經常使用簡單的枚舉來表示我們的實體狀態。當我們引入很大程度上取決於國家的行爲時,或者國家轉型必須遵守某些業務規則時,問題就出現了。狀態模式和域驅動設計
看看下面的例子(使用一個枚舉來表示狀態):
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
}
}
你可以看到,這個類將很快成爲我們添加的拒絕方法,完全相當冗長,刪除等
相反,我們可以引入State模式,它允許我們封裝每個州作爲一個對象:
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;
}
}
這可以很容易地過渡betwee n種狀態,進行基於當前狀態的邏輯或者,如果我們需要增加新規定:
// transition state
vacancy.State.Approve();
// conditional
model.ShowRejectButton = vacancy.State.CanReject();
這種封裝似乎更清潔,但給予足夠的狀態,這些也可以變得非常冗長。我讀Greg Young's post on State Pattern Misuse,建議使用多態性代替(所以我會有ApprovedVacancy,UnapprovedVacancy等類),但不能看到這將如何幫助我。
我應該將這種狀態轉換委託給域服務還是我在這種情況下使用狀態模式是正確的?
如果消費者不應該直接改變狀態,這意味着我最終將爲我的實體上的每個狀態轉換結束。那麼我在這裏獲得了什麼? – 2012-04-04 15:26:11
您可以獲得封裝並且不存在大量的if語句:)以下是正式的好處:1.它針對不同狀態本地化特定於狀態的行爲和分區行爲。它使狀態轉換顯式化。 3.狀態對象可以共享。 – 2012-04-04 15:58:45
謝謝。最後一個問題 - 我們堅持空缺到文檔存儲(RavenDB)。你會建議持久化一個用於加載相關狀態對象的枚舉嗎?或者只是存儲整個狀態對象 – 2012-04-04 16:12:33