Pensieri e migliori pratiche su classi e membri statici [chiuso]


11

Sono molto curioso di pensare e delle migliori pratiche del settore in merito ai membri statici o a intere classi statiche. Ci sono degli aspetti negativi a questo o partecipa a qualche anti-pattern?

Vedo queste entità come "classi / membri di utilità", nel senso che non richiedono o richiedono un'istanza della classe per fornire la funzionalità.

Quali sono i pensieri generali e le migliori pratiche del settore al riguardo?

Vedi le classi e i membri di esempio di seguito per illustrare ciò a cui mi riferisco.

// non-static class with static members
//
public class Class1
{
    // ... other non-static members ...

    public static string GetSomeString()
    {
        // do something
    }
}

// static class
//
public static class Class2
{
    // ... other static members ...

    public static string GetSomeString()
    {
        // do something
    }
}

Grazie in anticipo!


1
L' articolo MSDN su Classi statiche e metodi statici offre un trattamento abbastanza buono.
Robert Harvey,

1
@Robert Harvey: Anche se l'articolo a cui hai fatto riferimento è utile, non fornisce molto in termini di migliori pratiche e di quali sono alcune insidie ​​quando si usano le classi statiche.
Bernard,

Risposte:


18

In generale, evitare la statica, in particolare qualsiasi tipo di stato statico.

Perché?

  1. La statica causa problemi con la concorrenza. Poiché esiste solo un'istanza, è naturalmente condivisa tra l'esecuzione simultanea. Queste risorse condivise sono la rovina della programmazione concorrente e spesso non devono essere condivise.

  2. La statica causa problemi con i test unitari. Qualsiasi framework di test unitari che valga la pena è saltato contemporaneamente. Quindi ti imbatti nel n. 1. Peggio ancora, complichi i tuoi test con tutte le cose di installazione / smontaggio, e le attività di hacking in cui ti imbatterai per provare a "condividere" il codice di installazione.

Ci sono anche molte piccole cose. La statica tende ad essere inflessibile. Non puoi interfacciarli, non puoi ignorarli, non puoi controllare i tempi della loro costruzione, non puoi usarli bene in generici. Non puoi davvero versioni.

Vi sono certamente usi della statica: i valori costanti funzionano alla grande. I metodi puri che non rientrano in una singola classe possono funzionare alla grande qui.

Ma in generale, evitali.


Sono curioso di sapere quanto sia incapace di competere. Puoi espanderci? Se intendi che è possibile accedere ai membri senza segregazione, ha perfettamente senso. I tuoi casi d'uso per la statica sono ciò a cui li utilizzo in genere: valori costanti e metodi puri / di utilità. Se questo è il migliore e il 99% di casi d'uso per la statica, allora questo mi dà un livello di comfort. Inoltre, +1 per la tua risposta. Ottima informazione
Thomas Stringer

@ThomasStringer - solo che più punti di contatto tra thread / attività significano maggiori opportunità per problemi di concorrenza e / o maggiori perdite di prestazioni durante la sincronizzazione.
Telastyn,

Quindi, se un thread sta attualmente accedendo a un membro statico, altri thread devono attendere fino a quando il thread proprietario non rilascia la risorsa?
Thomas Stringer

@ThomasStringer - forse, forse no. La statica (quasi in quasi tutte le lingue) non è diversa da qualsiasi altra risorsa condivisa al riguardo.
Telastyn,

@ThomasStringer: Sfortunatamente in realtà è peggio di così, a meno che non si contrassegni il membro volatile. Non si ottiene alcuna garanzia dal modello di memoria senza dati volatili, quindi la modifica di una variabile in un thread potrebbe non riflettere immediatamente o affatto.
Phoshi,

17

Se la funzione è "pura" non vedo problemi. Una funzione pura opera solo nei parametri di input e fornisce un risultato basato su quello. Non dipende da alcuno stato globale o contesto esterno.

Se guardo il tuo esempio di codice:

public class Class1
{
    public static string GetSomeString()
    {
        // do something
    }
}

Questa funzione non accetta alcun parametro. Pertanto, probabilmente non è puro (l'unica implementazione pura di questa funzione sarebbe quella di restituire una costante). Presumo che questo esempio non sia rappresentativo del tuo problema reale, sto semplicemente sottolineando che questa probabilmente non è una funzione pura.

Facciamo un esempio diverso:

public static bool IsOdd(int number) { return (number % 2) == 1; }

Non c'è nulla di sbagliato nel fatto che questa funzione sia statica. Potremmo persino trasformarlo in una funzione di estensione, consentendo al codice client di diventare ancora più leggibile. Le funzioni di estensione sono fondamentalmente solo un tipo speciale di funzioni statiche.

Telastyn menziona correttamente la concorrenza come un potenziale problema con i membri statici. Tuttavia, poiché questa funzione non utilizza lo stato condiviso, non ci sono problemi di concorrenza qui. Mille thread possono chiamare questa funzione contemporaneamente senza problemi di concorrenza.

Nel framework .NET, i metodi di estensione esistono da un po 'di tempo. LINQ contiene molte funzioni di estensione (ad es. Enumerable.Where () , Enumerable.First () , Enumerable.Single () , ecc.). Non li vediamo male, vero?

I test unitari possono spesso trarre vantaggio quando il codice utilizza astrazioni sostituibili, consentendo al test unitario di sostituire il codice di sistema con un doppio di test. Le funzioni statiche vietano questa flessibilità, ma ciò è per lo più importante ai confini del livello architettonico, dove vogliamo sostituire, ad esempio, un livello di accesso ai dati effettivo con un livello di accesso ai dati falso .

Tuttavia, quando si scrive un test per un oggetto che si comporta in modo diverso, a seconda che un numero sia pari o dispari, non è necessario poter sostituire la IsOdd()funzione con un'implementazione alternativa. Allo stesso modo, non vedo quando dobbiamo fornire Enumerable.Where()un'implementazione diversa ai fini del test.

Esaminiamo quindi la leggibilità del codice client per questa funzione:

Opzione a (con la funzione dichiarata come metodo di estensione):

public void Execute(int number) {
    if (number.IsOdd())
        // Do something
}

Opzione b:

public void Execute(int number) {
    var helper = new NumberHelper();
    if (helper.IsOdd(number))
        // Do something
}

La funzione statica (estensione) rende il primo pezzo di codice molto più leggibile e la leggibilità è molto importante, quindi usa le funzioni statiche dove appropriato.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.