A menudo utilizamos enumeraciones simples para representar un estado en nuestras entidades. El problema surge cuando presentamos un comportamiento que depende en gran medida del estado o en el que las transiciones de estado deben cumplir con ciertas reglas comerciales.Patrón de estado y diseño impulsado por dominio
Tome el siguiente ejemplo (que utiliza una enumeración para representar estado):
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
}
}
Se puede ver que esta clase pronto llegar a ser bastante detallado a medida que añadimos métodos para rechazar, retire etc.
lugar podemos introducir el patrón de Estado, lo que nos permite encapsular cada estado como objeto:
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;
}
}
Esto hace que sea fácil hacer la transición entr n estados, realizan lógica basada en el estado actual o añadir nuevos estados si necesitamos:
// transition state
vacancy.State.Approve();
// conditional
model.ShowRejectButton = vacancy.State.CanReject();
Esta encapsulación parece más limpio pero dado suficientes estados, estos también pueden llegar a ser muy detallado. Leí Greg Young's post on State Pattern Misuse que sugiere usar polimorfismo en su lugar (por lo que tendría las clases ApprovedVacancy, UnapprovedVacancy etc.), pero no puedo ver cómo me ayudará esto.
¿Debo delegar tales transiciones de estado a un servicio de dominio o es correcto mi uso del patrón de estado en esta situación?
si el consumidor no debe cambiar el estado directamente, seguramente esto significa que terminaré con un método para cada transición de estado en mi entidad. Entonces, ¿qué estoy realmente ganando aquí? –
Obtiene la encapsulación y la ausencia de un montón de sentencias if :) Aquí están los beneficios oficiales: 1. Localiza comportamiento de estado y particiones específicas para diferentes estados. 2. Hace explícitas las transiciones de estado. 3. Los objetos de estado se pueden compartir. –
Gracias.Una última pregunta: estamos persistiendo en la vacante en una tienda de documentos (RavenDB). Sugeriría persistir una enumeración que se utiliza para cargar el objeto de estado relevante o simplemente almacenar todo el objeto de estado –