Buone pratiche per tenere dati immutabili

3

Mi chiedo quale sia la prassi migliore per detenere dati immutabili , più specificamente in C # .

Ad esempio, diciamo che ho un oggetto immutabile chiamato Foo .

public sealed class Foo {
    public int Bar { get; }

    public Foo(int bar) {
        Bar = bar;
    }
}

Attualmente, ho conservato questi oggetti in un static class in questo modo.

public static class FooList {
    private static List<Foo> fooList;

    static Foo {
        fooList = new List<Foo>();
        fooList.Add(new Foo(1));
        fooList.Add(new Foo(2));
    }

    public static Foo GetFoo(int index) {
        if (index >= 0 && index < fooList.Count) {
            return fooList[index];
        }

        // I don't know if this is right, but besides the point
        throw;
    }
}

Da lì, qualsiasi classe può avere il proprio riferimento a un oggetto Foo chiamando GetFoo(int) . Tuttavia, ho letto recentemente che static classes dovrebbe essere evitato a causa della loro difficile manutenzione (non conosco la ragione specifica, ma suppongo che sia perché non possono essere istanziati).

Se questo è il caso, quale sarebbe la migliore pratica per contenere dati immutabili in questa situazione? Sono a conoscenza del Singleton Pattern , ma non so se questa è la migliore pratica per questa situazione.

    
posta Hayden 22.08.2015 - 10:27
fonte

4 risposte

4

Fondamentalmente, non vi è alcun problema descritto nella domanda che in realtà ha bisogno di una soluzione. Non hai fornito alcun motivo per l'esistenza di un detentore Foo o cosa dovrebbe essere in grado di fare. Quindi, davvero, FooList è completamente inutile.

Se hai bisogno di un Foo, c'è una funzione linguistica per questo- new Foo(1) . Non c'è motivo per qualsiasi ulteriore partecipazione da cedere alla classe Foo.

Modifica: puoi utilizzare una cache non statica molto semplice e semplicemente passare attorno alla cache.

public class FooCache {
    private Dictionary<int, Foo> cache = new Dictionary<int, Foo>();
    public FooCache() {}
    public Foo GetFoo(int i) {
        if (!cache.ContainsKey(i))
            cache[i] = new Foo(i);
        return cache[i];
    }
}

Questo tiene più direttamente gli oggetti Foo che vuoi realmente, invece di creare un elenco preimpostato e poi sperare che siano corretti, è molto più trasparente, puoi comunque usare new Foo se ti serve a, e puoi avere più istanze di esso se vuoi (es. test unitari).

    
risposta data 22.08.2015 - 12:09
fonte
8

Il problema è che hai effettivamente creato una variabile globale per accedere a questi oggetti, la classe Foolist. Questo ha degli svantaggi per cose come la testabilità ed è in generale solo un design scarso.

Lo stato globale non aiuta a rendere il codice facile da leggere e le classi che consumano non possono mai essere isolate dal Foos (cercare up mocking) quando testano.

Evita la staticità e passa i foos oi foolist in giro come variabili di istanza.

    
risposta data 22.08.2015 - 11:01
fonte
2

Il vantaggio dell'immutabilità è che non importa ciò che fai con i tuoi riferimenti ad esso. Globali, classi statiche e singleton sono molto meno problematici delle loro controparti mutabili, perché non è necessario sincronizzare le mutazioni e tenere traccia delle dipendenze degli ordini create. Tuttavia, hanno ancora problemi con il mock-out per il test dell'unità.

Dall'altra parte dello spettro, puoi avere tutti i riferimenti che vuoi, o anche copie a titolo definitivo. Questo perché non devi preoccuparti di propagare eventuali modifiche alle altre copie, poiché non ci sono sono nessuna modifica. Questa è la parte più difficile a cui le persone possono abituarsi, se sono abituate alla mutabilità, ma di solito è la più semplice da mantenere e conserva i benefici per il mocking nei test unitari.

    
risposta data 22.08.2015 - 18:19
fonte
0

(Questa voce è un wiki. Non esitare a migliorare questa risposta

Qui è argomentato come sia preferibile l'uso di static per immutable e concetti correlati.

  • Le costanti stesse sono definite globali. Oggetti che non cambieranno non solo durante il runtime, ma non avranno valori alternativi (come un percorso del filesystem che potrebbe cambiare in base alla configurazione) a priori sarà altrettanto buono da definire statico.
  • Queste sarebbero istanze su valori indicizzati che non cambierebbero tra le esecuzioni:
    • Una cache di valori precompilati (ad esempio alcuni motori grafici contengono tabelle trigonometriche , specialmente nei primi anni '90, quando non c'era alcun punto fluttuante nel processore).
    • Come un schema FlyWeight , dove tenteremmo di salvare la memoria utilizzando le istanze canoniche piuttosto che avere molti oggetti con lo stesso valore. Ad esempio, se cariciamo il cognome "Smith" 10.000 volte, potremmo tenere in memoria quel valore 10.000 volte o mantenere la prima istanza in un dizionario e fare riferimento alla stessa istanza canonica per ogni duplicato posteriore.
  • C'è un dibattito in corso sul fatto che i valori statici siano qualcosa da evitare (come in questa popolare domanda in Overflow dello stack sul pattern Singleton )

    • L'alternativa sarebbe creare un'istanza che racchiuda tutti questi valori (e quindi passando quel contesto come parametro a qualsiasi metodo che ne ha bisogno).
    • In Test Driven Development che consente di utilizzare istanze personalizzate per il test. Tuttavia, dal momento che parliamo di dati immutabili, potrebbe trattarsi di una "costante universale" o di alcuni dati personalizzati che potrebbero essere caricati facilmente da un file di configurazione alternativo.
    • Il fatto di passare il contesto come parametro, potrebbe finire in situazioni imbarazzanti, in cui uno o più oggetti contestuali / componenti sono passati lungo i metodi, senza essere molto chiari quale sia il loro uso (un caso estremo di Timbro accoppiamento). Espresse un po 'intensamente:

    I have seen several developers go to extraordinary lengths to avoid a global because they considered using one as an admission of failure..

risposta data 23.05.2017 - 14:40
fonte

Leggi altre domande sui tag