"statico" come indizio semantico sull'apolidia?

11

Recentemente ho intrapreso un refactoring di un progetto di medie dimensioni in Java per tornare indietro e aggiungere test unitari. Quando mi sono reso conto di quanto fosse dolore deridere singoletti e statici, alla fine ho "ottenuto" quello che ho letto su di loro per tutto questo tempo. (Sono una di quelle persone che hanno bisogno di imparare dall'esperienza, oh, va bene.)

Quindi, ora che sto usando Spring per creare gli oggetti e collegarli, mi sto liberando di static parole chiave a sinistra ea destra. (Se potessi potenzialmente volerlo prendere in giro, non è proprio statico nello stesso senso in cui Math.abs () è, giusto?) Il fatto è che avevo preso l'abitudine di usare static per denotare che un metodo non 'fare affidamento su qualsiasi stato dell'oggetto. Ad esempio:

//Before
import com.thirdparty.ThirdPartyLibrary.Thingy;
public class ThirdPartyLibraryWrapper {
    public static Thingy newThingy(InputType input) {
         new Thingy.Builder().withInput(input).alwaysFrobnicate().build();
    }
}

//called as...
ThirdPartyLibraryWrapper.newThingy(input);
//After
public class ThirdPartyFactory {
    public Thingy newThingy(InputType input) {
         new Thingy.Builder().withInput(input).alwaysFrobnicate().build();
    }
}

//called as...
thirdPartyFactoryInstance.newThingy(input);

Quindi, qui è dove arriva il tocco delicato. Mi è piaciuto il vecchio modo perché la lettera maiuscola mi ha detto che, proprio come Math.sin (x), ThirdPartyLibraryWrapper.newThingy (x) ha fatto la stessa cosa allo stesso modo ogni volta. Non esiste uno stato oggetto per modificare il modo in cui l'oggetto fa ciò che sto chiedendo di fare. Ecco alcune possibili risposte che sto considerando.

  • Nessun altro si sente così, c'è qualcosa che non va in me. Forse non ho proprio interiorizzato il modo OO di fare le cose! Forse sto scrivendo in Java ma penso in FORTRAN o in somesuch. (Che sarebbe impressionante dal momento che non ho mai scritto FORTRAN.)
  • Forse sto usando staticità come una sorta di proxy per l'immutabilità per gli scopi del ragionamento sul codice. Detto questo, quali indizi dovrei che ho nel mio codice per qualcuno che viene avanti per mantenerlo per sapere cosa è statico e cosa non lo è?
  • Forse questo dovrebbe venire gratis se scelgo metafore oggetto buone? per esempio. thingyWrapper non suona come ha lo stato indipendente dal% co_de fasciato che può essere mutabile. Allo stesso modo, un Thingy suona come dovrebbe essere immutabile, ma potrebbe avere diverse strategie che vengono scelte nella creazione.
posta leoger 10.12.2012 - 22:59
fonte

3 risposte

12

I liked the old way because the capital letter told me that, just like Math.sin(x), ThirdPartyLibraryWrapper.newThingy(x) did the same thing the same way every time. There's no object state to change how the object does what I'm asking it to do.

Questo è il modo giusto per farlo, sì. Detto questo, static non conferisce alcuna garanzia di immutabilità o persistenza dello stato. Che tu lo usi come suggerimento per tali garanzie ha senso, ma non è affatto garantito.

Considera quanto segue:

public static class Logger
{
    public static int LogLevel { get; set; }

    public static void Log(string message, int logLevel)
    {
        if (logLevel >= LogLevel)
        {
            // logs the message, but only if it is important enough.
        }
    }
}

Questa classe non solo mantiene lo stato, ma il comportamento del metodo Logger.Log() cambia quando tale stato viene modificato. È un esercizio perfettamente legittimo di un modello di classe static , ma non ha nessuna delle garanzie semantiche che stai suggerendo.

    
risposta data 10.12.2012 - 23:24
fonte
5

A mio parere quello che stai dicendo - tutte le funzioni statiche per essere nullipotent - è un buon modo OO di scrivere codice nella maggior parte dei casi, ma non credo che quando guardi una funzione statica devi automaticamente presumere che non avere effetti collaterali. La situazione potrebbe essere più complessa; prendi per esempio la funzione Class.forName(String) che sembra essere stateless ma in realtà carica una classe nella memoria e alla fine istanzia campi statici / avvia l'inizializzatore statico; questo è un esempio di funzione idempotente (eventuali chiamate successive alla prima non fanno alcuna differenza) ma non è una funzione pura (non si può dire che non abbia effetti collaterali). Questa è anche una buona scelta, ma potrebbero esserci casi in cui tre chiamate distinte per la stessa funzione producono tre risultati diversi; per esempio se chiami Thread.currentThread() in un'applicazione multi-thread non c'è garanzia che riceverai sempre lo stesso thread.

That being said, what clues should I have in my code for someone coming along to maintain it to know what's stateful and what's not?

Una soluzione adeguata è quella di documentare (Javadoc ad esempio); inoltre, dal nome della funzione e da quello che fa a volte si può dedurre che la funzione statica è una funzione pura. Ad esempio, non c'è motivo per qualcuno di credere che Assert.assertTrue(boolean) di JUnit cambierebbe qualche stato da qualche parte. D'altra parte quando viene chiamata una funzione come System.clearProperty(String) , è abbastanza ovvio che ci saranno effetti collaterali.

    
risposta data 10.12.2012 - 23:24
fonte
4

That being said, what clues should I have in my code for someone coming along to maintain it to know what's stateful and what's not?

Puoi renderli statici. FxCop over nel mondo C # ti spingerà a fare cose statiche che non fanno variabili membro di riferimento. Questa è la cosa giusta da fare (di solito).

When I realized what a pain it was to mock singletons and statics, I finally "got" what I've been reading about them all this time.

Spostandoli tutti su istanze forse non è l'approccio giusto. Invece, disaccoppia le dipendenze dai metodi statici dalle classi che li usano. È possibile testare i metodi statici in isolamento e quindi sostituire la dipendenza degli utenti quando devono essere testati.

    
risposta data 10.12.2012 - 23:15
fonte