Un ricordo con un altro nome?

4

Il libro GoF "Pattern di progettazione" descrive il modello Memento come un oggetto che incapsula il suo stato in un oggetto separato. Tuttavia, il libro descrive in modo specifico il memento da utilizzare con un custode specifico; nel loro esempio, un fornitore di annullamento / ripristino.

Tuttavia, questo pattern, specialmente in C #, quando il Memento è reso un struct (in entrambi i sensi tecnici e concettuali), può fornire molti vantaggi quando si fa una parte più generale di una classe:

  • Permetti una facile clonazione, che rende il caching, ect più facile e meno soggetto a errori
  • Permetti alla logica di persistenza di essere condivisa facilmente e con garbo dalle diverse versioni del modello che si estende su più domini
  • Visualizza le proprietà in un'interfaccia utente che altrimenti verrebbe incapsulata
  • Gestire le operazioni CRUD per le proprietà altrimenti incapsulate
  • Affrontare l'invidia per quanto riguarda l'invidiabilità quando è inevitabile, ad esempio una classe che regola un'operazione tra due altre classi (un cliente prenota un volo o un volo aggiunge un cliente? Evitiamo questa domanda mettendo la prenotazione di un volo in un luogo separato)
  • Possiamo usare la comoda sintassi di intilizer dell'oggetto senza rendere modificabili le nostre proprietà. Inoltre, evitiamo costruttori che sono gonfiati con argomenti
  • E, naturalmente, persistenza di proprietà altrimenti incapsulate

Possiamo anche usare il memento come una sorta di versione di classe della classe implicitamente sicura per tutta l'applicazione.

Tuttavia, si potrebbe obiettare, molti di questi hanno appena abusato del modello allo scopo di aggirare le carenze linguistiche.

Ad esempio:

public class Computer
{
     public Computer(ComputerMemento state)
     {
         _state = state;
     }

     private ComputerMemento _state;
     public ComputerMemento State
     {
         get
         {
              var copy = _state;
              return copy;
         }
     }

     public void DoSomeComputerThing() { }
     public void DoComputerStuff() { }
     public int GetSomeComputerCalculation() { }
}

public struct ComputerMomento
{
    public string MachineName;
    public float ProcessorSpeed;
    public long AmountOfRam;
    public int CPUCores;
}

La precedente classe% co_de può ora esporre una rappresentazione modificabile dei suoi stati pur essendo in grado di certificare (sebbene in modo facilmente aggirabile) che le modifiche al suo stato (tramite i suoi metodi) siano valide e supportate. Fondamentalmente, il consumatore può selezionare il livello di ignoranza desiderato.

Questo uso esteso di quello che sembra essere il pattern del memento è ancora il pattern del memento? In caso contrario, ha un nome?

EDIT: nel codice precedente, poiché Computer s viene passato per valore, lo stato è immutabile da classi esterne.

    
posta TheCatWhisperer 01.01.2018 - 20:06
fonte

1 risposta

7

Il pattern del ricordo

L'intento del ricordo è chiaramente definito in GoF:

Without violating encapsulation, capture and externalize an object's internal state so that the object can be restored to this state later.

La chiave di quel modello è la sua doppia interfaccia: per il mondo esterno il ricordo è una scatola nera chiusa che può essere passata a chiunque abbia bisogno di ricevere un'interfaccia stretta ), ma solo il suo originatore è consentito aprirlo (interfaccia wide ).

L'esempio di implementazione di GoF utilizza C ++ friend per implementare la doppia interfaccia che garantisce il rispetto dell'incapsulamento. Nelle lingue in cui non è disponibile questa funzione, il ricordo potrebbe essere implementato utilizzando due interfacce distinte .

Il tuo modello

Il tuo "ricordo" espone pubblicamente lo stato. Questo interrompe l'incapsulamento e altri rispetto al mittente possono modificare questo stato salvato. Questa è una significativa divergenza dal ricordo del GoF.

Nel tuo design, per fortuna, assicurati che il memento permetta solo modifiche valide. Ma questo richiede:

  • una duplicazione della logica di controllo dello stato (sia in Computer an ComputerMomento ). Per oggetti complessi questo potrebbe essere una fonte di bug;
  • o l'uso dell'interfaccia di memnto per modificare lo stato interno dell'oggetto.

Inoltre, non sei più libero di modificare lo stato interno come desideri: supponiamo che tu decida che CPUCores non sarà più un valore memorizzato, ma un valore dedotto da CPUmodel . Ciò richiederebbe quindi di cambiare l'interfaccia del memento e tutto il codice che utilizza l'interfaccia estesa del memento.

Non è un ricordo, ma ...

Sembra che tu utilizzi ComputerMomento sia come stato interno che come copia esterna di uno stato precedente.

Questo sembra molto vicino a un modello di stato semplificato in cui un Computer avrebbe solo un singolo stato. Tuttavia, qui non si ha un tipico comportamento dipendente dallo stato di GoF, poiché tutto il comportamento è implementato in Computer .

Quindi alla fine hai usato solo la composizione per isolare lo stato interno di Computer dal suo comportamento. Dal punto di vista dei nomi, IMHO sarebbe meno ambiguo chiamarlo ComputerState o ComputerConfiguration piuttosto che ComputerMomento .

    
risposta data 01.01.2018 - 23:17
fonte

Leggi altre domande sui tag