Funzioni statiche vs classi

8

Diciamo che voglio costruire alcune funzioni di utilità per fare alcune matematiche di base con BigDecimal s, per esempio voglio avere una funzione che calcoli la media di un List<BigDecimal> .

Qual è l'approccio migliore? Una funzione statica o una classe di utilità?

public static BigDecimal computeAverage(List<BigDecimal> numbers)

o

public class BigDecimalUtil

public computeAverage(List<BigDecimal> numbers)
    
posta S4M 18.02.2012 - 23:36
fonte

6 risposte

9

Probabilmente darò via le mie inclinazioni C # nel peggiore dei modi, ma consiglierei sempre metodi statici all'interno delle classi di utilità. Questo ti dà il meglio di entrambi i mondi. I vantaggi organizzativi della classe con l'usabilità dei metodi accessibili senza dover istanziare un oggetto per usarli. Se la tua classe di utilità ha un motivo per variare occasionalmente il suo comportamento, allora sei già in una buona posizione per farlo introducendo l'ereditarietà / interfacce in un secondo momento, se necessario. Se desideri che il tuo design sia un po 'più portatile, scoprirai che il paradigma sarà più facilmente trasferibile ad altre lingue OO.

    
risposta data 19.02.2012 - 03:55
fonte
5

Se vuoi fare funzioni di utilità, collegate da un tema, crea una classe per loro, rendile statiche in quella classe e costruisci un costruttore di quella classe privata, per eliminare la possibilità di dare casualmente un'istanza. Quindi, usa la seconda variante, ma nascondi il costruttore.

public class BigDecimalUtil

public computeAverage(List<BigDecimal> numbers)

private BigDecimalUtil(){super();}

C'è ancora una possibilità: non fare costruttore e rendere astratta questa classe. Ma in questo modo non puoi usare l'istanza della classe non solo all'esterno, ma anche al suo interno. Quindi, penso, questa seconda variante è troppo severa per te. Scegli te stesso.

    
risposta data 18.02.2012 - 23:44
fonte
4

Sono d'accordo con @Gangnus sul fatto che una classe "wrapper" statica abbia senso se i singoli metodi di classe saranno sempre usati in isolamento, e questa sarà spesso una buona risposta.

Tuttavia, potrebbe esserci qualche valore in una classe non statica, con metodi non statici, se si hanno probabilità che i calcoli correlati vengano usati insieme. Ad esempio, costruisci un oggetto ListStatsUtil con List<BigDecimal> passato nel costruttore, potrebbe essere conveniente accedere a getStandardDeviation , getVariance e getAverage in sequenza senza passare di nuovo nell'oggetto. Ciò potrebbe essere più elegante, ma potrebbe anche migliorare, specialmente se sono coinvolte operazioni computazionalmente costose che possono essere ottimizzate attraverso le operazioni condividendo lo stato privato all'interno dell'oggetto.

public ListStatsUtil {
    private final List<BigDecimal> numbers;
    public ListStatsUtil(List<BigDecimal> numbers) {
        this.numbers = numbers;
    }
    public BigDecimal getAverage() {
        // return average of this.numbers
    }
    public BigDecimal getStandardDeviation() {
        // return std dev of this.numbers
    }
    public BigDecimal getVariance() {
        // return variance of this.numbers
    }
    public BigDecimal getMax() {
        // return max of this.numbers
    }
    public BigDecimal getMin() {
        // return min of this.numbers
    }
}
    
risposta data 19.02.2012 - 03:51
fonte
1

Ho votato per la soluzione di codingoutloud e mi piacerebbe approfondire un po '.

Il wrapping delle raccolte in classi è qualcosa che sono venuto a cercare di fare sempre - la mia regola è "Non passare mai una collezione naked". I più grandi fallimenti di OO che ho visto è quando le persone hanno paura di aggiungere metodi a cui appartengono. Nel tuo caso i metodi appartengono alla collezione (Totalmente ovviamente se ci pensi), quindi mettili lì avvolgendo la raccolta, e per mettere la ciliegina sulla torta, esponi solo la funzionalità di cui hai bisogno al di fuori della tua nuova classe (come codingoutloud fatto) in modo che tu possa guardare la tua singola, piccola classe e capire facilmente tutto ciò che manipola quella raccolta.

Non devi risolvere tutti i possibili problemi perché è tutto il tuo codice, puoi modificare il wrapper della raccolta con la stessa facilità con cui puoi modificare le altre classi che interagiscono con esso. Ciò ti consente di inserire altro codice nella classe, se necessario; se non esci mai la raccolta diventerà subito ovvio quale codice appartiene al wrapper.

Questo ti dà anche il controllo completo sulla collezione in modo che tu possa evitare che entri in uno stato incoerente con la sua funzione (Ad esempio, se nessuna voce nella raccolta può essere nullo, basta impedire a chiunque di inserire un valore null!)

La maggior parte del codice OO errato che abbia mai visto è stata creata perché qualcuno ha scelto di scrivere utilità statiche o codice inline appartenente a oggetti a cui non è stato possibile aggiungere codice anziché utilizzare gli oggetti inoffensivi nel proprio codice che potrebbero modificare.

    
risposta data 19.03.2015 - 00:58
fonte
0

Se non sbaglio e Java è un puro linguaggio OO, non puoi avere funzioni senza doverle includere in una classe.

Quindi la tua risposta è: entrambi, una funzione statica racchiusa in una classe di utilità statica, non diversamente dalla classe Math.

    
risposta data 16.08.2012 - 14:49
fonte
-2

Che ne dici di un'interfaccia CalcAverageStrategy che è stata iniettata e puoi quindi implementare le implementazioni media / mediana / modalità se necessario, se necessario.

Ogni implementazione è facile da testare e anche facile da simulare per i test.

    
risposta data 25.03.2015 - 21:29
fonte

Leggi altre domande sui tag