Sto modellando una radice aggregata, che ha diverse azioni che eseguono operazioni contro altre entità, come ci si aspetterebbe. L'aggregato, tuttavia, ha uno stato e molte di queste operazioni possono essere eseguite solo quando l'aggregato si trova in uno stato particolare.
Ho creato un'implementazione del modello di stato, in modo che l'aggregato delegasse semplicemente l'azione all'oggetto concreto di stato. Tuttavia, ora che l'ho implementato, mi sono trovato con le seguenti preoccupazioni:
- Ci sono operazioni che possono essere invocate in più di uno stato, quindi ho finito per ripetere le implementazioni.
- Ci sono operazioni che generano eventi di dominio, quindi ho dovuto passare la raccolta di eventi della root in modo che possano aggiungere gli eventi correttamente.
- Alcune operazioni richiedono l'accesso ai membri privati della radice aggregata, quindi ho finito per dichiararle come interne (C #) o per creare metodi interni che modificano i membri privati.
Quindi ora mi chiedo se l'implementazione è valsa la pena o se l'oggetto stato deve avere solo proprietà CanPerformOperation1 e lasciare che la radice aggregata controlli questa proprietà e, se false, lancia una InvalidOperationException.
Il seguente codice è un riassunto di ciò che sto tentando di provare.
interface IState {
void Register(DomainName domain, CustomerCode code);
void Activate(ActivationManifest manifest);
void Lock();
void Unlock();
void EnsureConsistency();
}
class NewState : IState {
// can only call Register method, transitions to RegisteredState
}
class RegisteredState : IState {
// can only call Activate method, transitions to ActiveState
}
class ActiveState : IState {
// can call Lock or EnsureConsistency
// Lock transitions to locked state
// EnsureConsistency can transition to RestrictedState or ActiveState
}
class LockedState : IState {
// can only call Unlock, transitions to ActiveState
}
class RestrictedState : IState {
// can only call EnsureConsistency, which can transition
// to ActiveState or RestrictedState
}
class Tenant {
private IState _state = new NewState(this);
private readonly UserAccountCollection _accounts;
private readonly LicenseCollection _licenses;
private readonly ApplicationCollection _applications;
// had to make these internal accesors to be used by
// EnsureConsistency in ActiveState and RestrictedState
internal UserAccountCollection _accounts => _accounts;
internal Application RegisterApplication(AppKey key, UserAccount admin){
// this method is called by the RegisteredState.Activate method
// so what's the point of delegating?
}
internal License RegisterLicense(LicenseKey key) {
// this method is also called by the RegisteredState.Activate
// method, just like the one above.
}
// etc
}
Ora, ciò aumenterà solo di complessità, poiché il cliente mi richiede di aggiungere altri metodi che dipendono dallo stato. Quindi mi stavo chiedendo se dovrei semplicemente aggiungere proprietà come CanRegisterApplication, CanRegisterLicense, ecc., E quindi gli stati agiranno solo come flag switch.
Quale sarebbe il modo corretto di implementare ciò che sto cercando di ottenere? O forse sto ricevendo il modello di stato sbagliato?