Perché e quando dovrei rendere una classe "statica"? Qual è lo scopo della parola chiave "statica" sulle classi?


47

La staticparola chiave su un membro in molte lingue significa che non dovresti creare un'istanza di quella classe per poter avere accesso a quel membro. Tuttavia, non vedo alcuna giustificazione per fare un'intera classe static. Perché e quando dovrei fare un corso static?

Quali vantaggi ottengo dal fare una lezione static? Voglio dire, dopo aver dichiarato una classe statica, si dovrebbero comunque dichiarare statici tutti i membri a cui si desidera avere accesso senza istanza.

Ciò significa che, ad esempio, la Mathclasse potrebbe essere dichiarata normale (non statica), senza influire sul modo in cui gli sviluppatori programmano. In altre parole, rendere una classe statica o normale è in qualche modo trasparente per gli sviluppatori.


Se stai programmando in stile Func Prog come Rich Hickey, questo può essere utile.
Giobbe

1
Secondo me, le classi statiche sono semplicemente una stampella attraverso la quale C # tenta di nascondere un enorme difetto di progettazione nel linguaggio. Perché strutturare un linguaggio attorno a questa ideologia insensata di tutto-per-essere-una-classe, solo per introdurre una sintassi aggiuntiva in modo da poter imbrogliare e aggirare questa inutile restrizione. Se C # avesse appena permesso le funzioni libere fin dall'inizio, non ci sarebbe bisogno di classi statiche.
antred

Risposte:


32

Rende ovvio agli utenti come viene utilizzata la classe. Ad esempio, sarebbe una completa assurdità scrivere il seguente codice:

Math m = new Math();

C # non deve proibirlo, ma poiché non serve a nulla, potrebbe anche dirlo all'utente. Alcune persone (incluso me) aderiscono alla filosofia secondo cui i linguaggi di programmazione (e le API ...) dovrebbero essere il più restrittivi possibile per renderli difficili da usare in modo errato: le uniche operazioni consentite sono quindi quelle significative e (si spera) corrette.


3
Non sono d'accordo con quella filosofia. Il problema che ho è che deve cambiare. Quindi, sebbene abbia avuto senso limitare prima d'ora quella limitazione ostacola il nostro sviluppo per esigenze future. E la libreria legacy che siamo costretti a usare per interfacciarci con il vecchio sistema (quello che hai scritto, sigillato e fissato in tutte le classi) non ci fornisce alcun modo per estendere o modificare quel codice che hai scritto. Solo perché non hai motivo di creare un'istanza della tua lezione non significa che non ne avrò bisogno in futuro. Mentre la statalizzazione di una classe di utilità ha senso, considera anche il futuro.
SoylentGray,

19
@Chad Quindi la libreria è mal progettata. L'estensione delle classi che non sono state progettate per l'estensione alla fine non funziona, quindi è meglio creare la classe sealedin primo luogo. Riconosco che non tutte le persone sono d'accordo con questo sentimento, ma i commenti non sono un buon posto per discuterne. Ma nel caso di staticquesto problema non si pone nemmeno: l'istanza nonSystem.Math avrà mai senso.
Konrad Rudolph,

1
@Konard, se dichiari tutti i membri della Mathclasse come statici senza dichiarare la Mathclasse come statica, puoi comunque usarla, senza bisogno di istanziazioni.
Saeed Neamati,

11
@Saeed - Questo è vero, ma potresti anche istanziare la classe, che non serve a nulla. Cosa devo fare con un'istanza della classe di matematica? Per mostrare esplicitamente l'intento della classe (nessuna istanza necessaria o desiderata), è contrassegnato static.
Corbin,

3
@Saeed Ribaltiamolo: ti propongo di leggere di nuovo la mia risposta poiché sembra che tu l'abbia frainteso: i tuoi commenti non sono correlati alla mia risposta. Non ho mai detto che devi scrivere new Math().
Konrad Rudolph,

24

StackOverflow ha una grande discussione su questo argomento . Per comodità di riferimento, lo copierò e incollerò qui, per conto del suo autore, Mark S. Rasmussen :

Ho scritto i miei pensieri sulle classi statiche in un thread precedente :

Adoravo le classi di utilità riempite con metodi statici. Fecero un grande consolidamento dei metodi di aiuto che altrimenti sarebbero dovuti causare ridondanza e inferno di manutenzione. Sono molto facili da usare, nessuna istanza, nessuno smaltimento, solo il fuoco e lo scordo. Immagino che questo sia stato il mio primo inconsapevole tentativo di creare un'architettura orientata ai servizi - molti servizi senza stato che hanno fatto il loro lavoro e nient'altro. Man mano che cresce un sistema, tuttavia, arrivano i draghi.

Polimorfismo

Supponiamo di avere il metodo UtilityClass.SomeMethod che ronza felicemente. All'improvviso dobbiamo modificare leggermente la funzionalità. La maggior parte delle funzionalità è la stessa, ma dobbiamo comunque cambiare un paio di parti. Se non fosse stato un metodo statico, avremmo potuto creare una classe derivata e modificare i contenuti del metodo secondo necessità. Dato che è un metodo statico, non possiamo. Certo, se abbiamo solo bisogno di aggiungere funzionalità prima o dopo il vecchio metodo, possiamo creare una nuova classe e chiamare quella vecchia al suo interno - ma questo è semplicemente disgustoso.

Interfaccia guai

I metodi statici non possono essere definiti tramite interfacce per motivi logici. E poiché non possiamo ignorare i metodi statici, le classi statiche sono inutili quando dobbiamo passarle in giro dalla loro interfaccia. Questo ci rende incapaci di usare le classi statiche come parte di un modello di strategia. Potremmo correggere alcuni problemi passando delegati anziché interfacce.

analisi

Questo in pratica va di pari passo con i problemi dell'interfaccia menzionati sopra. Poiché la nostra capacità di scambiare le implementazioni è molto limitata, avremo anche problemi a sostituire il codice di produzione con il codice di prova. Ancora una volta, possiamo racchiuderli ma ci richiederà di modificare grandi parti del nostro codice solo per poter accettare wrapper invece degli oggetti reali.

Favorisce le chiazze

Poiché i metodi statici vengono generalmente utilizzati come metodi di utilità e i metodi di utilità di solito hanno scopi diversi, finiremo rapidamente con una grande classe piena di funzionalità non coerente - idealmente, ogni classe dovrebbe avere un unico scopo all'interno del sistema. Preferirei avere un numero di lezioni cinque volte maggiore se i loro scopi sono ben definiti.

Creep di parametro

Per cominciare, quel piccolo metodo statico carino e innocente potrebbe prendere un singolo parametro. Man mano che la funzionalità aumenta, vengono aggiunti un paio di nuovi parametri. Presto verranno aggiunti ulteriori parametri che sono facoltativi, quindi creiamo sovraccarichi del metodo (o semplicemente aggiungiamo valori predefiniti, nelle lingue che li supportano). In poco tempo, abbiamo un metodo che accetta 10 parametri. Sono richiesti solo i primi tre, i parametri 4-7 sono opzionali. Ma se viene specificato il parametro 6, è necessario compilare anche 7-9 ... Se avessimo creato una classe con il solo scopo di fare ciò che ha fatto questo metodo statico, potremmo risolverlo prendendo i parametri richiesti nel costruttore e consentire all'utente di impostare valori opzionali tramite proprietà o metodi per impostare più valori interdipendenti contemporaneamente. Anche,

Consumatori esigenti di creare un'istanza di classi senza motivo

Uno degli argomenti più comuni è, perché chiedere ai consumatori della nostra classe di creare un'istanza per invocare questo singolo metodo, senza averne successivamente bisogno? La creazione di un'istanza di una classe è un'operazione molto economica nella maggior parte delle lingue, quindi la velocità non è un problema. L'aggiunta di una riga aggiuntiva di codice al consumatore è un costo basso per porre le basi di una soluzione molto più sostenibile in futuro. Infine, se si desidera evitare la creazione di istanze, è sufficiente creare un wrapper singleton della propria classe che consenta un facile riutilizzo, sebbene ciò richieda che la classe sia apolide. Se non è stateless, è comunque possibile creare metodi wrapper statici che gestiscono tutto, offrendo comunque tutti i vantaggi a lungo termine. Finalmente,

Solo un Sith si occupa di assoluti

Certo, ci sono eccezioni alla mia antipatia per i metodi statici. Le vere classi di utilità che non comportano alcun rischio di gonfiamento sono casi eccellenti per metodi statici, come System.Convert. Se il tuo progetto è unico e non richiede requisiti per la manutenzione futura, l'architettura complessiva non è davvero molto importante - statica o non statica, non importa - la velocità di sviluppo è comunque importante.

Standard, standard, standard!

L'uso dei metodi di istanza non impedisce di utilizzare anche metodi statici e viceversa. Finché c'è un ragionamento dietro la differenziazione ed è standardizzata. Non c'è niente di peggio che guardare un livello aziendale tentacolare con diversi metodi di implementazione.


12
Hmmm, non so che avrei copiato e incollato un'intera risposta qui. Forse link e parafrasi, includere un punto di vista alternativo dal momento che menzioni una "discussione", condividi la tua esperienza?
Corbin,

2
"Solo un Sith si occupa di assoluti" - non l'avevo mai visto così prima ... ma è PERFETTO. Mi ha fatto lol.
Brook,

4
@Corbin: Mark ha avuto un'ottima risposta. Gli ho dato credito e ho copiato / incollato per facilità di riferimento. Le mie opinioni su questa questione corrispondono a quelle di Mark. Non vedo il punto del tuo commento, se non quello di iniziare il dibattito.
Rick,

1
@Rick: la risposta copiata è piuttosto lunga e parafrasare sarebbe sicuramente di aiuto. Solo una frase del tipo "Non è solo che non sono davvero utili, possono persino nuocere, come mostra questo post SO:" mi farebbe saltare rapidamente perché vedo che non sono le informazioni che stavo cercando.
Blubb,

@Simon: LOL I 1 + 'ed il tuo post. Nel tentativo di smettere di litigare per qualcosa di così stupido, accetto semplicemente. :) Spero che il poster originale abbia trovato utile la mia risposta / copia e incolla.
Rick,

16

Sono sorpreso che nessun altro abbia menzionato che le staticclassi consentono metodi di estensione - estendere in modo sicuro un tipo esistente (inclusa l' aggiunta di definizioni di metodo alle interfacce ) che non si possiede. Ad esempio, cosa è in Scala

trait MyFoo {
  def foo: Int
  def plusFoo(a: Int) = foo + a
}

può essere espresso in C # come

public interface IMyFoo {
  int Foo();
}

public static class MyFooExtensions {
  public static int PlusFoo(this IMyFoo f, int a) {
    return f.Foo() + a;
  }
}

hai trovato l'ago nel pagliaio. +1
Saeed Neamati,

3

Per me, una classe statica (in C #) è un po 'come chiamare una funzione.

Per esempio

public static string DoSomething(string DoSomethingWithThisString){}

Passo una stringa e torno indietro una stringa. Tutto è contenuto in quel metodo. Nessun accesso alla variabile membro, ecc.

Onestamente, principalmente il suo utilizzo per me è stato quello di ridurre le righe di codice:

Perchè fare:

MyClass class = new MyClass();
String s = class.DoSomething("test");

Quando posso farlo:

String s = MyClass.DoSomething("test");

Quindi, userei le classi statiche in quei casi, quando volevo fare qualcosa senza la necessità di una classe e significherebbe scrivere meno.

I punti Mark S. sono validi, ma per me se ho alcuni metodi di utilità è solo più semplice far finta che sto chiamando una funzione per fare riferimento a loro come una linea.

Potrebbe essere semplicistico, ma è principalmente quello che ho usato static.


1
new MyClass (). DoSomething ("test") è ancora valido. Lo uso molto per i costruttori di dati di test.
JoanComasFdz
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.