Cancellare un oggetto dominio e assicurarsi che eventuali riferimenti rimanenti siano successivamente inutilizzabili

3

Se ho una classe di dominio con un metodo di istanza Delete() . Qual è il modo migliore per garantire che eventuali riferimenti avanzi a un'istanza che ha "cancellato sé stesso" siano successivamente inutilizzabili?

Questa domanda è molto simile al mio, ma penso che il PO sia più in generale interessato a come l'API nel suo complesso dovrebbe essere informata delle delezioni che si verificano altrove e reagiscono a tali eliminazioni. Qualsiasi menzione di come dovrebbero comportarsi le istanze cancellate è puramente periferica.

Ad esempio, un punto elenco dice:

If my wrapper object finds out that its unerlying [sic] storage has been deleted (e.g. because of access to an uncached property returned an error), should it now mark itself as Deleted (so that all access to properties and methods return some sort of ObjectDeletedException) or should it just clear all caches and allow future calls to fail naturally.

Sono più interessato a come implementare l'errore che dovrebbe verificarsi quando vengono utilizzate proprietà o metodi dell'istanza eliminata. Posso mettere un controllo del gateway all'interno di ogni proprietà e metodo che genera un'eccezione (come indicato nella citazione sopra), ma ciò creerebbe un codice estremamente fragile da allora ogni sviluppatore futuro - incluso me - dovrebbe ricordare di aggiungere quell'assegno quando si creano nuove proprietà o metodi.

Inoltre, non ritengo che tali verifiche siano sufficienti, in quanto la sola presenza di un riferimento a un oggetto potrebbe essere significativa, indipendentemente dalle sue proprietà o metodi sottostanti. Ad esempio, un client della mia API potrebbe contenere riferimenti a tali istanze che credono esistano e, se uno si è cancellato, quell'istanza non dovrebbe più essere valida e dovrebbe causare ogni sorta di inferno. Forse potrebbe solo generare un evento "NotifyDeleted" e lasciare che sia il cliente a rispondere, ma non sono sicuro che sia sufficiente.

    
posta rory.ap 07.10.2015 - 16:32
fonte

3 risposte

1

Stiamo parlando di classi e istanze (come per il primo paragrafo) o di oggetti e riferimenti (come per titolo)?

In entrambi i casi, puoi:

Conserva l'elemento cancellato (anche se contrassegnato come eliminato), quindi disabilita l'accesso all'elemento eliminato. Occasionalmente, dovrai determinare quando gli elementi eliminati non hanno più riferimenti in modo da poterli rilasciare / liberare, altrimenti avrai una perdita di memoria.

-o -

Trovate tutti gli usi (istanze o riferimenti) e cancellateli e parte dell'eliminazione dell'elemento. Dovrai farlo in modo ricorsivo e atomicamente o eliminando prima i riferimenti, quindi gli elementi.

-o -

Non consentire l'eliminazione a causa di utilizzi in sospeso, costringendo l'utente o il cliente a rintracciarli e cancellarli per primi.

Lavorerei questo problema dall'esperienza lato client per vedere cosa si aspettano gli utenti del dominio.

Qualunque soluzione tu usi, ci sono tecniche che rendono queste cose più facili. Gli spazi problema / soluzione qui sono simili alla gestione della memoria, (alloc / free), garbage collection e gestione dell'integrità referenziale (database).

Il conteggio dei riferimenti funziona se tutto ciò che serve è sapere se esiste un riferimento e il tuo dominio preclude i cicli. Tuttavia, i riferimenti a ritroso possono essere utili in modo da poter trovare più rapidamente i riferimenti; tracciare le tue strutture come quelle del GC è un'altra opzione.

Ancora, puoi utilizzare un database SQL e sfruttare le eliminazioni a cascata.

In ogni caso, penso che l'esperienza del dominio sia la più importante, e inizierei con i requisiti di progettazione da quella prospettiva, quindi sceglierò tra le varie soluzioni che soddisfano le esigenze del tuo business / dominio.

Ad esempio, vuoi un effetto trash-can-like in cui puoi supportare annullare l'eliminazione o annullare? Vuoi mantenere oggetti che hanno riferimenti (agli elementi cancellati), ma cancellare o annullare il riferimento? Anche l'intero oggetto di riferimento dovrebbe essere eliminato senza ulteriori indugi? I tuoi clienti / utenti si aspettano di poter chiedere "quali sono gli articoli che fanno riferimento a questo articolo" (solo di primo livello o, eventualmente, ricorsivamente in una query)? Quali sono le implicazioni sulla modifica multiutente dello stesso spazio (che un utente di cui un utente è a conoscenza è eliminato da un altro utente).

    
risposta data 07.10.2015 - 20:07
fonte
0

Il tuo aggregato dovrebbe occuparsi di ripulire eventuali riferimenti tra le entità sottostanti. Quindi questo lascia solo problemi con gli aggregati che fanno riferimento ad altri aggregati.

La rimozione dei riferimenti aggregati da altri aggregati può essere gestita con un Process Manager ... un componente che ascolta eventi specifici e, a sua volta, invia comandi. Tra le altre cose, è un modo per far accadere le cose tra gli aggregati senza che una transazione coinvolga più aggregati (il che limita la scalabilità e / o le prestazioni).

Tecnicamente, è possibile rimuovere i riferimenti aggregati-aggregati dal client subito dopo aver eliminato l'aggregazione. Ma ciò richiede un livello di fiducia (sia nell'intenzione che nella corretta gestione) nel client che potresti non avere o che vuoi assumere in futuro.

In passato, quando avevo bisogno che l'oggetto eliminato rispondesse "Mi dispiace, Dave, temo di non poterlo fare". Ho avuto il repository che restituisce un'interfaccia. (Molte persone lo fanno comunque come ovvio.)

public interface IMyDomainThing
{
    void Method1();
    void Method2();
    string Property1 { get; }
}

// repo method
public IMyDomainThing GetMyDomainThing(Guid id);

Quindi il repository stesso ha controllato se l'elemento è stato cancellato e restituisce una versione cancellata in quel caso:

public DeletedMyDomainThing: IMyDomainThing
{
    private void RaiseError()
    {
        throw new NotSupportedException("Not allowed on a deleted object");
    }

    public void Method1() { RaiseError(); }
    public void Method2() { RaiseError(); }
    // not entirely sure this is necessary
    public string Property1 { get { RaiseError(); } }
}

Sì, la manutenzione su questo fa schifo, perché cambiare i membri pubblici richiede di toccare l'interfaccia, la classe non cancellata e la classe eliminata. Tuttavia, non lo chiamerei fragile, perché l'interfaccia ti offre il controllo della compilazione (e in VS, in fase di progettazione) per assicurarti che la tua versione cancellata abbia tutto compilato.

    
risposta data 07.10.2015 - 19:50
fonte
0

Breve risposta rapida

Esistono diverse tecniche per rilevare quando ci sono diversi riferimenti allo stesso oggetto [dominio] e l'oggetto viene rimosso.

Risposta lunga e noiosa

Esistono diverse tecniche per cancellare diversi riferimenti dello stesso oggetto.

E quelle tecniche possono essere combinate.

[1] Utilizza sempre un puntatore o un riferimento

Poiché l'oggetto è concettualmente "condiviso" da altri oggetti, usa un "riferimento" o un "puntatore" in tutti loro.

Non hai menzionato quale linguaggio di programmazione stavi applicando la tua domanda. In alcuni P.L. vengono usati i "puntatori", i "riferimenti" sono usati.

In alcuni P.L. come C ++ o Object Pascal, una variabile oggetto può essere dichiarata in due modi:

[1.1] Direct (variabile "allocato staticamente")

[1.2] O usando un "puntatore" ("variabili dinamiche")

E la sintassi per ogni modo è diversa.

In "riferimento" P.L. entrambi i concetti sono un po 'misti.

Molti programmatori usano una variabile standard, o una variabile non puntatore, la prima volta, e i puntatori, in seguito, usano sempre un puntatore o un riferimento.

[2] Usa il pattern di progettazione "Observer" (a.k.a. "Publisher-Subscriber")

Come @Christopher Francisco, menzioni che potresti voler usare il Pattern design del software "Observer", a.k.a. "Publisher-Subscriber", a.k.a. "Client-Server".

Informazioni di Wikipedia:

link

link

Fondamentalmente, quando un oggetto vuole fare qualcosa con se stesso, ha un set preregistrato di riferimenti ad altri oggetti, che notifica i cambiamenti.

In questo caso, l'oggetto da rimuovere, informa i contenitori o i proprietari dei riferimenti, non i riferimenti stessi, che sarà rimosso.

[3] Usa pattern "BeforeEvent", "ExecuteEvent", "AfterEvent"

Questo di solito è confuso con il Pattern di progettazione "Observer", perché è mescolato con esso, molte volte.

Lo vedrete molto in G.U.I. controlli.

Fondamentalmente significa che un oggetto può dividere alcune azioni importanti in 3, "prima", "mentre" e "dopo". A volte il "prima" include la conferma dell'azione e, se l'azione viene annullata, gli altri 2 metodi non vengono eseguiti.

Quindi questo:

...........................
..+---------------------+..
..|       SomeClass     |..
..+---------------------+..
..| [+] Delete()        |..
..+---------------------+..
...........................

Può diventare questo:

...........................
..+---------------------+..
..|      SomeClass      |..
..+---------------------+..
..| [#] BeforeDelete()  |..
..| [#] ExecuteDelete() |..
..| [#] AfterDelete()   |..
..+---------------------+..
..| [+] Delete()        |..
..+---------------------+..
...........................

E, naturalmente, il metodo pubblico Delete chiama gli altri metodi.

Se combinato con il modello di progettazione "Observer", in ogni azione, viene inviata una notifica a ciascun oggetto del sottoscrittore.

    
risposta data 07.10.2015 - 20:10
fonte

Leggi altre domande sui tag