Java - È una cattiva idea avere classi completamente statiche?

14

Sto lavorando a un progetto solista più ampio e in questo momento, e ho diverse classi in cui non vedo alcun motivo per creare un'istanza di.

La mia classe di dadi in questo momento, ad esempio, memorizza tutti i suoi dati staticamente e tutti i suoi metodi sono anche statici. Non ho bisogno di inizializzarlo perché quando voglio tirare i dadi e ottenere un nuovo valore, uso solo Dice.roll() .

Ho diverse classi simili che hanno solo una funzione principale come questa e sto per iniziare a lavorare su una sorta di classe "controller" che sarà responsabile di tutti gli eventi (come quando un giocatore si muove, e che turno attuale è) e ho scoperto che potrei seguire la stessa idea per questa classe. Non ho mai intenzione di creare più oggetti per queste classi specifiche, quindi sarebbe una cattiva idea renderli completamente statici?

Mi chiedevo se questo è considerato "cattiva pratica" quando si tratta di Java. Da quello che ho visto, la community sembra essere divisa su questo argomento? Ad ogni modo, mi piacerebbe avere qualche discussione su questo e anche i collegamenti alle risorse sarebbero fantastici!

    
posta HexTeke 11.04.2018 - 08:10
fonte

4 risposte

19

Non c'è niente di sbagliato nelle classi statiche che sono veramente statiche . Vale a dire, non esiste uno stato interno di cui parlare che possa far cambiare l'output dei metodi.

Se Dice.roll() sta semplicemente restituendo un nuovo numero casuale da 1 a 6, non sta cambiando stato. Certo, potresti condividere un'istanza Random , ma non considererei un cambiamento di stato come per definizione, l'output sarà sempre buono, casuale. È anche thread-safe quindi non ci sono problemi qui.

Vedrai spesso "Helper" finale o altre classi di utilità che hanno un costruttore privato e membri statici. Il costruttore privato non ha alcuna logica e serve solo per impedire a qualcuno di creare un'istanza della classe. Il modificatore finale porta a casa questa idea che questa non è una classe da cui vorresti mai provenire. È semplicemente una classe di utilità. Se fatto correttamente, non ci dovrebbero essere singoli o membri della classe che non siano essi stessi statici e definitivi.

Finché seguirai queste linee guida e non farai singleton, non c'è assolutamente nulla di sbagliato in questo. Lei menziona una classe di controller, e questo quasi certamente richiede cambiamenti di stato, quindi sconsiglio di usare solo metodi statici. Puoi fare molto affidamento su una classe di utilità statica, ma non puoi renderla una classe di utilità statica.

Che cosa è considerato un cambiamento di stato per una classe? Bene, escludiamo i numeri casuali per un secondo, poiché sono non deterministici per definizione e quindi il valore di ritorno cambia spesso.

Una funzione pura è una deterministica, vale a dire, per un determinato input, si otterrà uno ed esattamente un output. Vuoi che i metodi statici siano funzioni pure. In Java ci sono modi per modificare il comportamento dei metodi statici per mantenere lo stato, ma non sono quasi mai delle buone idee. Quando dichiari un metodo come statico , il tipico programmatore assumerà subito il fatto che si tratta di una funzione pura. Deviando dal comportamento previsto è come si tende a creare bug nel programma, in generale, e dovrebbe essere evitato.

Un singleton è una classe che contiene metodi statici come opposti alla "pura funzione" che puoi essere. Un singolo membro statico privato viene mantenuto internamente alla classe che viene utilizzata per garantire che esista esattamente un'istanza. Questa non è la migliore pratica e può metterti nei guai in seguito per una serie di motivi. Per sapere di cosa stiamo parlando, ecco un semplice esempio di un singleton:

// DON'T DO THIS!
class Singleton {
  private String name; 
  private static Singleton instance = null;

  private Singleton(String name) {
    this.name = name;
  }

  public static Singleton getInstance() {
    if(instance == null) {
      instance = new Singleton("George");
    }
    return instance;
  }

  public getName() {
    return name;
  }
}

assert Singleton.getInstance().getName() == "George"
    
risposta data 11.04.2018 - 08:30
fonte
9

Per dare un esempio delle limitazioni di una classe static , cosa succede se alcuni dei tuoi giocatori vogliono ottenere un leggero bonus sui loro tiri di dado? E sono disposti a pagare un sacco di soldi! : -)

Sì, potresti aggiungere un altro parametro, quindi Dice.roll(bonus) ,

In seguito avrai bisogno di D20.

Dice.roll(bonus, sides)

Sì, ma alcuni giocatori hanno l'abilità "supremamente capace" in modo che non possano mai "armeggiare" (tira un 1).

Dice.roll(bonus, sides, isFumbleAllowed) .

Questo sta diventando complicato, non è vero?

    
risposta data 11.04.2018 - 16:33
fonte
3

Nel caso particolare di una classe Dice, penso che l'utilizzo di metodi di istanza piuttosto che statici renderà il test molto più semplice.

Se vuoi testare qualcosa che usi un'istanza di Dadi (ad esempio una classe di gioco) e poi dai tuoi test, puoi iniettare qualche forma di test double di Dice che restituisce sempre una sequenza fissa di valori. Il tuo test può verificare che il gioco abbia il risultato giusto per quei tiri di dado.

Non sono uno sviluppatore Java, ma penso che sarebbe molto più difficile farlo con una classe Dice completamente statica. Vedi link

    
risposta data 11.04.2018 - 22:01
fonte
0

Questo è in realtà noto come Modello Monostate , dove ogni istanza (e anche una "non-istanza") sta condividendo il loro stato. Ogni membro è un membro della classe (ad esempio, nessun membro dell'istanza). Sono comunemente usati per implementare classi di "toolkit" che raggruppano un insieme di metodi e costanti correlati a una singola responsabilità o requisito, ma non hanno bisogno di uno stato per funzionare (sono puramente funzionali). In effetti, Java viene fornito con alcuni di questi pacchetti (ad esempio, Math ).

Un po 'fuori tema: raramente sono d'accordo con la denominazione delle parole chiave in VisualBasic, ma in questo caso, penso che shared sia sicuramente più chiaro e semanticamente migliore (è condiviso tra le classi stesso e tutte le sue istanze) rispetto a static (rimane dopo il ciclo di vita dell'ambito in cui è dichiarato).

    
risposta data 11.04.2018 - 20:54
fonte