È buono o cattivo avvolgere oggetti mutabili in contenitori immutabili?

3

Se ho parti di codice che hanno bisogno di mutare la struttura dati sottostante ma altre che consumano, non mutano la struttura, è buona pratica creare un wrapper che non esponga le operazioni di mutazione?

Diciamo che ho un albero e voglio solo parti più alte del codice per poterlo iterare.

    
posta Vaughan Hilts 22.02.2015 - 14:37
fonte

5 risposte

3

È un approccio comune. Concettualmente, questo è esattamente lo stesso principio degli specificatori di accesso e simili, vale a dire che stai limitando quali operazioni possono essere utilizzate in modo che tu sappia che il codice è sicuro.

Può essere un sacco di sforzo e confusione produrre involucri per ogni situazione possibile, quindi vale la pena solo se c'è un corpus di codice abbastanza grande che ha bisogno di questo sottoinsieme specifico.

In generale, è sempre una buona cosa limitare i metodi il più possibile. L'unica domanda è quanto sforzo vale. Questo non è un compromesso che può essere fatto per te senza sapere davvero quanto ti costerà e quanto codice può usarlo.

    
risposta data 22.02.2015 - 15:39
fonte
3

Sì, l'incapsulamento e l'immutabilità sono buoni, ma è importante capire perché, perché stai colpendo proprio il posto sbagliato, come Erik Meijer descrive nel suo articolo sottotitolato La programmazione" Principalmente funzionale "non funziona .

L'incapsulamento è buono quando si lavora per disaccoppiare un'interfaccia dalla sua implementazione. Smette di essere buono quando lo guardi per essere una sorta di sistema di sicurezza che protegge i tuoi dati pubblici da tutti quei malvagi programmatori in fondo al corridoio che scrivono il codice chiamante. Quello che spesso accade in quella situazione è che più codice ha bisogno del riferimento illimitato di quanto non si prevedesse, e si finisce con un sacco di hack che lo convertono avanti e indietro, o con la classe unrestricted che cerca di fare troppo.

L'immutabilità ha un gran numero di benefici, quasi tutti scompaiono quando provi a farlo a metà strada. Ad esempio, non sarai in grado di cambiare l'albero senza reimpostare ogni iteratore in tutti i thread che attualmente lo accedono.

Stai molto meglio semplicemente rendendolo immutabile fino in fondo. Ciò ti consente di approfittare di tutti i vantaggi dell'immutabilità e non ti interesserà chi ha accesso all'API di inserimento / cancellazione, perché sta solo cambiando la loro versione dell'albero.

    
risposta data 23.02.2015 - 01:20
fonte
0

L'immutabilità non è un obiettivo finale, di per sé. L'immutabilità è uno strumento. Come tutti gli strumenti, ha i suoi usi appropriati, i suoi vantaggi e svantaggi. Raggiungerlo con oggetti mutabili esistenti è più difficile di quanto sembri.

Considera un array ordinario:

var pokerHand = new Cards[5];

Possiamo creare una struttura dati usando un array come backing field e scrivendo un indicizzatore per questo:

public class ImmutableArray<T>
{
    T[] array;

    public this T(int index)
    {
        get { return array[index]; }
    }
}

Eliminando il setter dall'indicizzatore, hai effettivamente reso immutabile l'accesso ai membri, giusto? Bene, non esattamente. Poiché l'elemento restituito dall'indicizzatore è un tipo di riferimento, puoi comunque sostituire l'oggetto detenuto da quel tipo di riferimento e ora hai un nuovo oggetto in quella posizione nell'array.

var item = myPokerHand[5];
item = new Card("KS"); // myPokerHand[5] now contains a new Card

Per proteggere il contenuto dell'array originale, devi fare una copia dell'oggetto e restituirlo.

    public this T(int index)
    {
        get { return array[index].MemberwiseClone(); } // if you can.
    }

Tieni presente che MemberwiseClone è un copia superficiale , non una copia profonda. Fare questo correttamente potrebbe significare scrivere un metodo Clone che copia fedelmente tutti i membri del tuo oggetto, alcuni dei quali potrebbero anche essere riferimenti mutevoli.

Per tutti questi motivi, è meglio utilizzare le raccolte immutabili già fornite dal framework .NET, come ReadOnlyCollection , raccolte progettate da zero per essere immutabili.

Per le proprie collezioni e oggetti, la limitazione periodica dell'accesso ai membri privati è generalmente una buona cosa, per ragioni che spero siano ovvie (cfr. incapsulamento).

Ulteriori letture

Immutabilità in C # prima parte: tipi di immutabilità

    
risposta data 22.02.2015 - 15:46
fonte
0

L'immutabilità ha due effetti: uno, non posso modificare un oggetto immutabile. Due, nessuno può modificare un oggetto immutabile alle mie spalle. Se mi passi un contenitore immutabile contenente un oggetto mutevole, puoi ancora modificare quell'oggetto mutevole nel contenitore immutabile dietro la mia schiena, quindi non guadagno nulla dal fatto che sia immutabile. Dovresti garantire che una volta creato il contenitore immutabile, non modifichi più l'oggetto.

D'altra parte, puoi discutere se un contenitore immutabile di oggetti mutabili sia davvero "immutabile". Come una serie immutabile di stringhe, dove posso contare che l'array conterrà sempre le stesse stringhe, ma non posso contare su ciò che contengono le stringhe mutabili. Per molte situazioni, questo tipo di immutabilità non fornisce effettivamente le garanzie di cui un consumatore ha bisogno.

    
risposta data 23.02.2015 - 09:40
fonte
-3

La restrizione dell'accesso è sempre un approccio sicuro e può essere considerata una buona pratica. Questo è noto sotto il paradigma OOP come incapsulamento ed esiste per prevenire errori di programmazione che sono difficili da rilevare, come aggirare le vostre precauzioni di sicurezza nei metodi get / set cambiando direttamente una variabile. Questo rientra anche nel più ampio termine della programmazione difensiva, che è un paradigma di programmazione in cui si eliminano potenziali errori rendendo impossibile il loro commit in primo luogo.

Ci sono molti modi diversi per ottenere questo e avvolgere porzioni di codice in strutture di dati immutabili è sicuramente un'opzione praticabile, a seconda della lingua.

    
risposta data 22.02.2015 - 14:50
fonte

Leggi altre domande sui tag