Pensieri e best practice su classi e membri statici [chiuso]

9

Sono molto curioso dei pensieri e delle best practice del settore riguardanti i membri statici o intere classi statiche. Ci sono degli svantaggi o partecipa a qualche anti-pattern?

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

Quali sono i pensieri generali e le migliori pratiche del settore su questo?

Vedi le seguenti classi e membri di esempio per illustrare ciò che sto facendo riferimento.

// 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!

    
posta Thomas Stringer 19.03.2014 - 01:10
fonte

2 risposte

14

In generale, evita statics, specialmente qualsiasi tipo di stato statico.

Perché?

  1. Le statistiche causano problemi con la concorrenza. Poiché esiste una sola istanza, è naturalmente condivisa tra l'esecuzione simultanea. Quelle risorse condivise sono la rovina della programmazione concorrente e spesso non bisogno di essere condiviso.

  2. Le statistiche causano problemi con il test delle unità. Qualsiasi framework di test delle unità che valga la pena eseguire test di sale simultaneamente. Quindi ti imbatti in # 1. Peggio ancora, complichi i tuoi test con tutto il materiale di setup / teardown, e l'hacker a cui cadrai per provare a "condividere" il codice di installazione.

Ci sono anche un sacco di piccole cose. La statistica 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 metterli alla versione.

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

Ma in generale, evitalo.

    
risposta data 19.03.2014 - 02:00
fonte
11

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

Se guardo il tuo esempio di codice:

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

Questa funzione non richiede alcun parametro. Quindi, 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 solo sottolineando che probabilmente non è una funzione pura.

Prendiamo un esempio diverso:

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

Non c'è niente di sbagliato in questa funzione che è 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. Un migliaio di thread può chiamare questa funzione contemporaneamente senza problemi di concorrenza.

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

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

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

Quindi esaminiamo 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à conta molto, quindi usa le funzioni statiche dove opportuno.

    
risposta data 19.03.2014 - 09:14
fonte

Leggi altre domande sui tag