Non posso semplicemente usare tutti i metodi statici?

63

Qual è la differenza tra i due metodi UpdateSubject qui sotto? Ho sentito che usare metodi statici è meglio se vuoi semplicemente operare sulle entità. In quali situazioni dovrei andare con metodi non statici?

public class Subject
{
    public int Id {get; set;}
    public string Name { get; set; }

    public static bool UpdateSubject(Subject subject)
    {
        //Do something and return result
        return true;
    }
    public bool UpdateSubject()
    {
        //Do something on 'this' and return result
        return true;
    }
}

So che otterrò molti calci dalla community per questa domanda davvero fastidiosa, ma non potevo impedirmi di chiederlo.

Questo diventa impraticabile quando si tratta di ereditarietà?

Aggiornamento:
Sta accadendo nel nostro posto di lavoro ora. Stiamo lavorando su un'applicazione web asp.net di 6 mesi con 5 sviluppatori. Il nostro architetto ha deciso di utilizzare tutti i metodi statici per tutte le API. Il suo ragionamento è che i metodi statici sono leggeri e avvantaggiano le applicazioni Web mantenendo il carico del server.

    
posta Alexander 03.08.2011 - 01:20
fonte

10 risposte

83

Vado con i problemi più evidenti dei metodi statici con i "parametri" espliciti:

  1. Si perde dispatch virtuale e successivamente polimorfismo. Non puoi mai sovrascrivere quel metodo in una classe derivata. Ovviamente è possibile dichiarare un metodo new ( static ) in una classe derivata, ma qualsiasi codice che lo accede deve essere a conoscenza dell'intera gerarchia di classi e fare controlli e casting espliciti, che è precisamente ciò che OO dovrebbe evitare .

  2. Una sorta di estensione di # 1, non puoi sostituire istanze della classe con un'interfaccia , perché le interfacce (nella maggior parte delle lingue) non possono dichiarare metodi static .

  3. La verbosità non necessaria. Che è più leggibile: Subject.Update(subject) o solo subject.Update() ?

  4. Controllo degli argomenti. Di nuovo dipende dal linguaggio, ma molti compileranno un controllo implicito per garantire che l'argomento this non sia null per impedire a un bug di riferimento nullo di creare condizioni di runtime non sicure (tipo di sovraccarico del buffer). Non usando i metodi di istanza, dovresti aggiungere questo controllo esplicitamente all'inizio di ogni metodo.

  5. È confuso. Quando un programmatore normale e ragionevole vede un metodo static , naturalmente supporrà che non richieda un valido istanza (a meno che non richieda più istanze, come un metodo di confronto o di uguaglianza, o ci si aspetta che sia in grado di operare su riferimenti null ). Vedere i metodi statici usati in questo modo ci farà fare un doppio o forse triplo take, e dopo la quarta o la quinta volta saremo stressati e arrabbiati e Dio ti aiuterà se conosciamo il tuo indirizzo di casa.

  6. È una forma di duplicazione. Ciò che accade quando invochi un metodo di istanza è che il compilatore o il runtime cercano il metodo nella tabella dei metodi del tipo e lo invoca usando this come argomento. Fondamentalmente stai ri-implementando ciò che il compilatore già fa. Stai violando DRY , ripetendo lo stesso parametro ancora e ancora con metodi diversi quando non è necessario.

È difficile concepire qualsiasi motivo buono per sostituire i metodi di istanza con metodi statici. Per favore no.

    
risposta data 03.08.2011 - 02:06
fonte
12

Hai praticamente descritto esattamente come si esegue OOP in C, in cui sono disponibili solo metodi statici e "this" è un puntatore di struttura. E sì, è possibile eseguire il polimorfismo in runtime in C specificando un puntatore di funzione durante la costruzione da memorizzare come un elemento della struttura. I metodi di istanza disponibili in altre lingue sono solo zucchero sintattico che essenzialmente fa esattamente la stessa cosa sotto il cofano. Alcuni linguaggi, come python, sono a metà strada, dove il parametro "self" è elencato esplicitamente, ma una sintassi speciale per chiamarla gestisce l'ereditarietà e il polimorfismo per te.

    
risposta data 03.08.2011 - 05:20
fonte
10

Il problema con il metodo statico arriva nel momento in cui hai bisogno di una sottoclasse.

I metodi statici non possono essere sovrascritti nelle sottoclassi, quindi le nuove classi non possono fornire nuove implementazioni dei metodi, rendendole meno utili.

    
risposta data 03.08.2011 - 01:30
fonte
7

Se dichiari un metodo static , non devi creare un'istanza di un oggetto dalla classe (usando la parola chiave new ) per eseguire il metodo. Tuttavia, non è possibile fare riferimento a qualsiasi variabile membro a meno che non siano anche statiche, nel qual caso quelle variabili membro appartengono alla classe, non un oggetto istanziato specifico della classe .

In altre parole, la parola chiave static fa sì che una dichiarazione faccia parte della definizione della classe, quindi diventa un singolo punto di riferimento tra tutte le istanze della classe (oggetti istanziati dalla classe) .

Ne consegue, quindi, che se si desidera più copie in esecuzione della classe e non si desidera che lo stato (variabili membro) venga condiviso tra tutte le copie in esecuzione (ovvero ogni oggetto mantiene il proprio stato univoco) , quindi non puoi dichiarare statiche quelle variabili membro.

In generale, dovresti usare static classi e metodi solo quando stai creando metodi di utilità che accettano uno o più parametri e restituisci un oggetto di qualche tipo, senza effetti collaterali (es. cambia in variabili di stato nella classe)

    
risposta data 03.08.2011 - 01:29
fonte
3

Il motivo per cui le persone sostengono che "i metodi statici mostrano un cattivo design" non è necessariamente dovuto ai metodi, sono in realtà dati statici, impliciti o espliciti. Per implicito intendo QUALSIASI stato nel programma che non sia contenuto nei valori restituiti o nei parametri. Modificare lo stato in una funzione statica è un ritorno alla programmazione procedurale. Tuttavia, se la funzione non modifica lo stato, o delega la modifica dello stato alle funzioni dell'oggetto componente, in realtà è più un paradigma funzionale che procedurale.

Se non stai cambiando stato, i metodi e le classi statiche possono avere molti vantaggi. Rende molto più semplice garantire che un metodo sia puro, e quindi privo di effetti collaterali e qualsiasi errore sia pienamente riproducibile. Garantisce inoltre che diversi metodi in più applicazioni che utilizzano una libreria condivisa possano essere certi che otterranno gli stessi risultati in base allo stesso input, rendendo molto più facile sia la localizzazione degli errori che il testing unitario.

In definitiva non vi è alcuna differenza nella pratica tra oggetti sovradimensionati comunemente visti come "StateManager" e dati statici o globali. Il vantaggio dei metodi statici utilizzati correttamente è che possono indicare l'intenzione dell'autore di non modificare lo stato in revisori successivi.

    
risposta data 29.02.2012 - 04:51
fonte
2

Stai praticamente sconfiggendo l'intero punto degli oggetti quando lo fai. C'è una buona ragione per cui siamo praticamente passati dal codice procedurale al codice orientato agli oggetti.

Vorrei MAI dichiarare un metodo statico che prendesse il tipo di classe come parametro. Questo rende il codice più complesso senza alcun guadagno.

    
risposta data 03.08.2011 - 04:05
fonte
2

Questa è una domanda molto interessante che tende ad avere risposte molto diverse a seconda della comunità che stai chiedendo. Altre risposte sembrano essere C # o bias java: un linguaggio di programmazione che è (principalmente) puro orientato agli oggetti e ha una sorta di vista idiomatica su quale sia l'orientamento dell'oggetto.

In altre comunità, come C ++, l'orientamento agli oggetti è interpretato con maggiore libertà. Alcuni ben sanno che gli esperti hanno studiato l'argomento e, in realtà, concludono che le funzioni gratuite migliorano l'incapsulamento (l'enfasi è mia):

We've now seen that a reasonable way to gauge the amount of encapsulation in a class is to count the number of functions that might be broken if the class's implementation changes. That being the case, it becomes clear that a class with n member functions is more encapsulated than a class with n+1 member functions. And that observation is what justifies my argument for preferring non-member non-friend functions to member functions

Scott Meyers

Per coloro che non hanno familiarità con la terminologia C ++:

  • membro funzione = metodo
  • funzione non membro = metodo statico
  • non-amico = utilizza solo API pubblica
  • funzione non-membro non-amico = metodo statico che utilizza solo API pubblica

Ora, per rispondere alla tua domanda:

Can't I just use all static methods?

No, non dovresti usare sempre metodi statici.

Tuttavia, dovresti utilizzarli ogni volta che devi solo utilizzare l'API pubblica di una classe.

    
risposta data 30.07.2013 - 17:53
fonte
1

A seconda della lingua e di quello che stai cercando di fare, la risposta potrebbe essere che non c'è molta differenza, ma la versione static ha un po 'più di confusione.

Come la tua sintassi esemplificativa suggerisce Java o C #, penso che Thorbjørn Ravn Andersen abbia ragione nel sottolineare il problema di overriding (con late binding). Con un metodo statico, non vi è alcun parametro "speciale" per l'associazione tardiva su cui basarsi, quindi non è possibile avere un binding tardivo.

In effetti, un metodo statico è solo una funzione in un modulo, quel modulo che ha lo stesso nome della classe - non è affatto un metodo OOP.

    
risposta data 03.08.2011 - 01:49
fonte
1

Ci sono un sacco di ottime risposte qui, e sono molto più perspicaci e ben informati di qualsiasi altra che potrei mai avere come risposta, ma sento che c'è qualcosa che non viene affrontato:

"Il nostro architetto ha deciso di utilizzare tutti i metodi statici per tutte le API. Il suo ragionamento è che i metodi statici sono leggeri e avvantaggia le applicazioni Web mantenendo il carico del server ."

(l'enfasi è mia)

Il mio 2c su questa parte della domanda è questo:

In teoria, ciò che viene detto è vero: chiamare un metodo statico ha solo il sovraccarico di invocare effettivamente quel metodo. Chiamare un metodo non-statico (istanza) ha il sovraccarico extra della prima istanziazione dell'oggetto e, a un certo punto, distruggere l'istanza (manualmente o tramite una qualche forma di garbage collection automatica, a seconda della piattaforma utilizzata).

Suona un po 'l'avvocato del diavolo su questo: possiamo andare ancora oltre e dire cose del tipo:

  • questo può diventare davvero brutto se viene creata un'istanza per ogni chiamata del metodo (istanza) (invece di lasciarla statica e chiamarla in quel modo)

  • a seconda della complessità del costruttore, del tipo gerarchia, altri membri dell'istanza e altri fattori sconosciuti, il sovraccarico extra della chiamata al metodo non statico può variare e diventare veramente grande

In verità, IMHO, i punti di cui sopra (e l'approccio generale di "usiamo la statica perché sono più veloci") sono argomenti / valutazioni di Straw Man:

  • se il codice è buono e, più specifico per questo argomento, se le istanze vengono create solo quando necessario (e distrutte in modo ottimale), non si ottiene alcun sovraccarico dall'uso dei metodi di insance quando appropriato (perché se crei solo gli oggetti necessari, questi sarebbero stati creati anche se quel metodo è stato dichiarato come statico, dove altrimenti = overhead stesso istanza)

  • abusando della dichiarazione dei metodi statici in questo modo, è possibile nascondere alcuni problemi con il codice in relazione a come vengono create le istanze (poiché il metodo è statico un codice di instanciazione errato può passare inosservato fino a un momento successivo, e questo non è mai bene).

risposta data 30.07.2013 - 16:57
fonte
-3

in Java ...

I metodi statici non vengono sovrascritti ma sono nascosti e quindi sarebbe una grande differenza (problema?) nel caso di estensione della classe.

D'altra parte ho notato che i programmatori Java hanno la tendenza a pensare che tutti debbano essere oggetto, senza veramente capire perché, e non sono d'accordo.

Statico dovrebbe essere usato per codice specifico per la classe. Statico non funziona bene con l'ereditarietà.

alcuni buoni esempi di utilizzo di metodi statici sono funzioni indipendenti senza effetti collaterali.

vedi anche la parola chiave sincronizzata ...

    
risposta data 17.06.2015 - 17:58
fonte

Leggi altre domande sui tag