Una funzione può essere troppo breve?


125

Ogni volta che mi ritrovo a scrivere la stessa logica più di una volta, di solito la inserisco in una funzione in modo che vi sia un solo posto nella mia applicazione che devo mantenere quella logica. Un effetto collaterale è che a volte finisco con una o due funzioni di linea come:

function conditionMet(){
   return x == condition;
}

O

function runCallback(callback){
   if($.isFunction(callback))
     callback();
}

È una pratica pigra o cattiva? Lo chiedo solo perché ciò comporta un numero maggiore di funzioni che richiedono frammenti di logica molto piccoli.


3
No, non troppo breve. In C # farei "condition met" come proprietà, che è elegante, e prenderei in considerazione l'utilizzo Assert.AreEqual<int>(expected, actual, message, arg1, arg2, arg3, ...);. Il secondo va bene così com'è. Includerei potenzialmente un flag bool opzionale che detterebbe se lanciare un'eccezione / ecc. nel caso in cui il callback non sia una funzione.
Giobbe

38
Sì, solo in un caso: function myFunction () {}
Spooks

5
def yes(): return 'yes'
dietbuddha,

3
@Spooks - Sto dividendo i capelli qui, ma le funzioni vuote sono valide per almeno le classi dell'adattatore, ad esempio MouseMotionAdapter in download.oracle.com/javase/6/docs/api/java/awt/event/… . Naturalmente questo è solo un modo per aggirare le limitazioni linguistiche.
Aleksi Yrttiaho il

3
@dietbuddha: I requisiti sono appena cambiati - ora deve supportare due lingue per una demo la prossima settimana. Il tizio che ha scritto "def yes ()" era molto contento di averlo prima di cambiarlo in "def yes (: (IsFrench ()? 'Oui': 'Yes')"
Andrew Shepherd,

Risposte:


167

Hehe, oh signor Brown, se solo potessi convincere tutti gli sviluppatori che incontro a mantenere le loro funzioni così piccole, credetemi, il mondo del software sarebbe un posto migliore!

1) La tua leggibilità del codice aumenta di dieci volte.

2) Così facile da capire il processo del tuo codice a causa della leggibilità.

3) ASCIUTTO - Non ripetere te stesso - Ti stai conformando molto bene a questo!

4) Testabile. Le minuscole funzioni sono un milione di volte più facili da testare rispetto a quei 200 metodi di linea che vediamo troppo spesso.

Oh, e non preoccuparti di "saltare le funzioni" in termini di prestazioni. Le build "Release" e le ottimizzazioni del compilatore si occupano molto di questo per noi e le prestazioni sono il 99% delle volte da qualche altra parte nella progettazione dei sistemi.

Questo è pigro? - Al contrario!

Questa è una cattiva pratica? - Assolutamente no. Meglio tirare questo modo di fare metodi che le palle di catrame o "God Objects" che sono troppo comuni.

Continuate così, amico mio artigiano;)


40
Non stai rispondendo alla domanda, stai solo predicando la regola le cui applicazioni più estreme sono messe in discussione qui.

4
Non molto spesso trovo frustrante la limitazione di 1 solo voto. Ma, per questa risposta, +1 non sembra renderle giustizia.
Bevan,

4
+5 ... oh posso fare solo +1, oh bene! E per supportare MeshMan, suggerisco il seguente libro di Robert C. Martin codice Clean . Questo libro sta davvero cambiando il modo in cui ora programma.
Eric-Karl,

10
Risposta molto simpatica, ma non sono d'accordo con la maggior parte di essa: 1) Funzioni estremamente piccole danno come risultato più codice nel complesso, a causa di tutto l'impianto idraulico necessario per ciascuna funzione. Ciò può ridurre la leggibilità, soprattutto per un progetto davvero grande. Inoltre, dipende dalla lingua. 2) Dipende interamente dal punto 1 e quindi non ha nulla a che fare con la domanda. 3) Cosa? runCallback ripete "callback" quattro volte e tre volte fa riferimento alla stessa variabile per eseguire una singola funzione. 4) I metodi con oltre 200 linee non sono ovviamente testabili, ma c'è una lunga strada da quella a una riga.
l0b0

10
-1: La cosa più spaventosa qui è il numero di voti positivi assegnati a questa risposta.
Luca

64

Direi che un metodo refactored è troppo breve se uno dei due:

  • Duplica un'operazione primitiva, per nient'altro che renderlo un metodo:

Ex:

boolean isNotValue() {
   return !isValue();
}

o...

  • Il codice viene utilizzato solo una volta e il suo intento è facile da capire a colpo d'occhio.

Ex:

void showDialog() {
    Dialog singleUseDialog = new ModalDialog();
    configureDialog(singleUseDialog);
    singleUseDialog.show();
}

void configureDialog(Dialog singleUseDialog) {
    singleUseDialog.setDimensions(400, 300);
}

Questo potrebbe essere un modello valido, ma vorrei solo incorporare il metodo configureDialog (), in questo esempio, a meno che non intendessi sovrascriverlo o riutilizzare questo codice altrove.


7
Separare un metodo a riga singola nel secondo caso può essere utile per mantenere coerente il livello di astrazione dei metodi di chiamata. L'esempio fornito è sulla recinzione se viene utilizzato questo ragionamento: la larghezza e l'altezza esatte dei pixel sono troppo dettagliate per mostrare una finestra di dialogo?
Aleksi Yrttiaho il

2
Il metodo "isNotValue ()" ha un nome errato e deve essere rifattorizzato per dare un nome alla domanda del dominio attuale.

4
@Aleksi: non sono d'accordo; i dettagli sono già nascosti nel metodo showDialog () in questo esempio; non è necessario un doppio refactoring. L'esempio ha lo scopo di mostrare un caso d'uso isolato; se è necessario un modello con diverse configurazioni della finestra di dialogo in diversi casi, sarebbe opportuno tornare indietro e rifattorizzare una volta stabilito il modello.
RMorrisey,

1
@Thorbjorn: ho potuto vedere un caso, quando stai rispondendo a una domanda del dominio aziendale la cui logica potrebbe non essere ovvia. Sto solo sottolineando che ci sono alcuni casi in cui è eccessivo.
RMorrisey,

3
Forse questo è pignolo, ma direi che nei tuoi esempi il problema non è che la funzione è troppo breve, ma che non aggiungono valore descrittivo.
keppla,

59

Una funzione può essere troppo breve? In generale no.

Di fatto l'unico modo per garantire che:

  1. Hai trovato tutte le classi nel tuo design
  2. Le tue funzioni stanno facendo solo una cosa.

È di mantenere le funzioni il più piccolo possibile. Oppure, in altre parole, estrai le funzioni dalle tue funzioni fino a quando non puoi più estrarre. Io chiamo questo "Estrai fino allo sfinimento".

Per spiegarlo: una funzione è un ambito con blocchi di funzionalità che comunicano per variabili. Una classe è anche un ambito con blocchi di funzionalità che comunicano per variabili. Quindi una funzione lunga può sempre essere sostituita da una o più classi con metodo piccolo.

Inoltre, una funzione che è abbastanza grande da permetterti di estrarne un'altra funzione, sta facendo più di una cosa per definizione . Quindi, se è possibile estrarre una funzione da un'altra, è necessario estrarre quella funzione.

Alcune persone temono che ciò comporti una proliferazione di funzioni. Hanno ragione. Lo farà. In realtà è una buona cosa. È buono perché le funzioni hanno nomi. Se stai attento alla scelta di buoni nomi, queste funzioni fungono da segnali che indirizzano altre persone attraverso il tuo codice. In effetti, le funzioni ben definite all'interno di classi ben denominate all'interno di spazi dei nomi ben noti sono uno dei modi migliori per assicurarsi che i tuoi lettori NON si perdano.

C'è molto di più al riguardo nell'episodio III di Clean Code su cleancoders.com


5
Zio Bob! È bello vederti a bordo qui. Come previsto, consiglio fantastico. Non ho mai sentito il termine "Estrai fino allo sfinimento" prima e cercherò di usare questo termine in ufficio lunedì;).
Martin Blore,

1
Saresti disposto ad approfondire il tuo punto n. 1? Spiegare che con l'esempio sarebbe grandioso.
Daniel Kaplan,

53

Caspita, la maggior parte di queste risposte non è affatto molto utile.

Nessuna funzione deve essere scritta la cui identità è la sua definizione . Cioè, se il nome della funzione è semplicemente il blocco di codice della funzione scritto in inglese, allora non scriverlo come funzione.

Considera la tua funzione conditionMete questa altra funzione addOne(perdonami per il mio JavaScript arrugginito):

function conditionMet() { return x == condition; }

function addOne(x) { return x + 1; }

conditionMetè una corretta definizione concettuale; addOneè una tautologia . conditionMetè buono perché non sai cosa conditionMetcomporta solo dicendo "condizione soddisfatta", ma puoi capire perché addOneè sciocco se lo leggi in inglese:

"For the condition to be met is for x to equal condition" <-- explanatory! meaningful! useful!

"To add one to x is to take x and add one." <-- wtf!

Per l'amore di tutto ciò che potrebbe essere ancora santo, per favore, non scrivere funzioni tautologiche!

(E per lo stesso motivo, non scrivere commenti per ogni riga di codice !)


Alcuni dei costrutti linguistici più complessi potrebbero non essere familiari o difficili da leggere, rendendolo un trucco utile.

3
D'accordo, ciò che esattamente dovrebbe essere trasformato in una funzione dipenderebbe in gran parte dalla lingua in cui è stata scritta. Una funzione come addOne sarebbe utile se tu fossi in una lingua come VHDL, dove in realtà stai definendo il significato di aggiungerne una in un livello binario o di teoria dei numeri. Mi piacerebbe pensare che nessuna lingua là fuori sia così criptica che è difficile da leggere anche per programmatori esperti (forse brainf # ck), ma se è così, la stessa idea sarebbe valida dal momento che la funzione è effettivamente una traduzione dall'inglese in quella lingua - quindi il nome non è lo stesso della definizione.
Rei Miyasaka,

1
Sto parlando della funzione di identità delle cose dalla libreria standard di Haskell - Non penso che tu possa ottenere più "tautologico" di così :)
hugomg

1
@missingno Bah, questo è barare: D
Rei Miyasaka il

5
Se nominate le funzioni in base al loro scopo anziché al loro contenuto, smettono immediatamente di essere sciocche. Quindi i tuoi esempi potrebbero essere, ad esempio, essere function nametoolong() { return name.size > 15; }o function successorIndex(x) { return x + 1; } Quindi il problema con le tue funzioni è in realtà solo che il loro nome è cattivo.
Hans-Peter Störr,

14

Direi che se pensi che l'intenzione di alcuni codici possa essere migliorata aggiungendo un commento, quindi invece di aggiungere quel commento, estrai il codice nel suo metodo. Non importa quanto piccolo fosse il codice.

Ad esempio, se il tuo codice sarebbe stato simile a:

if x == 1 { ... } // is pixel on?

fai sembrare così invece:

if pixelOn() { ... }

con

function pixelOn() { return x == 1; }

O in altre parole, non si tratta della lunghezza del metodo, ma del codice di auto-documentazione.


5
Il mio stimato collega sottolinea che potresti anche scrivere if x == PIXEL_ON. L'uso di una costante può essere tanto descrittivo quanto l'uso di un metodo ed è un po 'più breve.
Tom Anderson,

7

Penso che sia esattamente quello che vuoi fare. In questo momento quella funzione potrebbe essere solo una o due righe ma nel tempo potrebbe crescere. Anche avere più chiamate di funzione ti permette di leggere le chiamate di funzione e capire cosa sta succedendo lì dentro. Questo rende il tuo codice molto ASCIUTTO (non ripetere te stesso) che è molto più gestibile.


4
Quindi cosa c'è che non va nel factoring più tardi, quando puoi provare che devi, invece di adesso, quando è solo un peso morto?
dsimcha,

Le funzioni non crescono da sole. IMHO gli esempi sono schifosi. conditionMetè un nome troppo generico e non accetta argomenti, quindi verifica alcuni stati? (x == xCondition) è nella maggior parte delle lingue e situazioni espressive come 'xConditition'.
utente sconosciuto

Sì, ed è per questo che vuoi avere un overhead del 75% nel tuo codice? La copertina singola scritta come 3 righe è in realtà il 300%.
Coder

5

Sono d'accordo con tutti gli altri post che ho visto. Questo è di buon stile.

Il sovraccarico di un metodo così piccolo può essere nullo poiché l'ottimizzatore può ottimizzare la chiamata e incorporare il codice. Un codice semplice come questo consente all'ottimizzatore di fare il suo meglio.

Il codice dovrebbe essere scritto per chiarezza e semplicità. Cerco di limitare un metodo a uno di due ruoli: prendere decisioni; o eseguire lavori. Ciò può generare metodi a una riga. Meglio sto facendo questo, meglio trovo il mio codice.

Codice come questo tende ad avere un'elevata coesione e un basso accoppiamento, il che è una buona pratica di codifica.

EDIT: una nota sui nomi dei metodi. Utilizzare un nome metodo che indica ciò che il metodo non fa come lo fa. Trovo verb_noun (_modifier) ​​è un buon schema di denominazione. Questo dà nomi come Find_Customer_ByName piuttosto che Select_Customer_Using_NameIdx. Il secondo caso tende a diventare errato quando il metodo viene modificato. Nel primo caso, è possibile scambiare l'intera implementazione del database dei clienti.


+1 per citare inline, quindi la considerazione principale in termini di prestazioni e funzioni brevi.
Garet Claborn,

4

Il refactoring di una riga di codice in una funzione sembra eccessivo. Potrebbero esserci casi eccezionali, come ver loooooong / comples lines o expessions, ma non lo farei se non sapessi che la funzione crescerà in futuro.

e il tuo primo esempio suggerisce l'uso di globali (che potrebbero o meno parlare di altri problemi nel codice), lo riforterebbe ulteriormente, e trasformerei queste due variabili come parametri:

function conditionMet(x, condition){
   return x == condition;
}
....
conditionMet(1,(3-2));
conditionMet("abc","abc");

L' conditionMetesempio potrebbe essere utile se la condizione era lunga e ripetitiva come:

function conditionMet(x, someObject){
   return x == ((someObject.valA + someObject.valB - 15.4) / /*...whole bunch of other stuff...*/);
}

1
Il suo primo esempio non fa pensare ai globali. Semmai, è un metodo coeso in una classe altamente coesa in cui la maggior parte delle variabili si trova sull'oggetto.
Martin Blore,

7
Quella conditionMetfunzione è solo un ==operatore prolisso . Questo è probabilmente inutile.

1
Sicuramente non uso i globali. @MeshMan, ecco esattamente da dove viene l'esempio ... un metodo su una classe.
Mark Brown,

1
@Mark Brown: @MeshMan: Ok, immagino che l'esempio di codice fosse troppo vago per saperlo con certezza ...
FrustratedWithFormsDesigner

Sto annusando un conditionMet (x, relation condition) {qui, dove passi x, '==' e relazione. Quindi non è necessario ripetere il codice per '<', '>', '<=', '! =' E così via. D'altra parte - la maggior parte delle lingue ha questi costrutti integrati mentre gli operatori (condizione x ==) fanno proprio questo. Le funzioni per le dichiarazioni atomiche sono troppo avanti.
utente sconosciuto

3

Considera questo:

Una semplice funzione di rilevamento delle collisioni:

bool collide(OBJ a, OBJ b)
{
    return(pow(a.x - b.x, 2) + pow(a.y - b.y, 2) <= pow(a.radius + b.radius, 2));
}

Se hai scritto quella "semplice" riga di codice nel tuo codice per tutto il tempo, potresti eventualmente commettere un errore. Inoltre, sarebbe davvero tortuoso scriverlo ancora e ancora.


Se abbiamo a che fare con C qui, potremmo semplicemente abusare #define;)
Cole Johnson

Puoi anche scambiarlo con l' ipotesi più lento ma a prova di trabocco se le dimensioni o le distanze diventano molto grandi. Questo, ovviamente, è molto più facile da fare una volta.
Matt Krause,

2

No, e questo è raramente un problema. Ora, se qualcuno ritiene che nessuna funzione dovrebbe essere più lunga di una riga di codice (se solo fosse così semplice), sarebbe un problema e in qualche modo pigro perché non sta pensando a ciò che è appropriato.


Non lo contarei in righe di codice, ma in espressioni. "(x == condition)" è atomico, quindi lo inserisco solo in un metodo / funzione, se usato più volte E potrebbe essere cambiato, come function isAdult () = { age >= 18; }ma sicuramente no isAtLeast18.
utente sconosciuto

2

Direi che sono troppo brevi, ma questa è la mia opinione soggettiva.

Perché:

  • Non vi è alcun motivo per creare una funzione se utilizzata solo una o due volte. Saltare a defs fa schifo. Soprattutto con il codice VS e C ++ incredibilmente veloce.
  • Panoramica della classe. Quando hai migliaia di piccole funzioni, mi fa arrabbiare. Mi piace quando posso visualizzare le definizioni delle classi e vedere rapidamente cosa fa, non come SetXToOne, SetYToVector3, MultiplyNumbers, + 100 setter / getter.
  • Nella maggior parte dei progetti, questi aiutanti perdono peso dopo una o due fasi di refactoring, e poi fai "cerca tutto" -> elimina per eliminare il codice obsoleto, di solito ~ 25% + di esso.

Le funzioni che sono lunghe sono cattive, ma le funzioni che sono più brevi di 3 righe ed eseguono solo 1 cosa sono ugualmente cattive IMHO.

Quindi direi di scrivere una piccola funzione solo se è:

  • 3+ righe di codice
  • Fa cose che gli sviluppatori minori potrebbero perdere (non so)
  • Esegue una convalida aggiuntiva
  • Viene utilizzato o verrà utilizzato almeno 3x
  • Semplifica l'interfaccia utilizzata di frequente
  • Non diventerà un peso morto durante il prossimo refactoring
  • Ha un significato speciale, ad esempio, la specializzazione del modello o qualcosa del genere
  • Fa un lavoro di isolamento - riferimenti const, influenza parametri mutabili, recupera membri privati

Scommetto che il prossimo sviluppatore (senior) avrà cose migliori da fare che ricordare tutte le funzioni di SetXToOne. Quindi si trasformeranno in peso morto abbastanza presto in entrambi i modi.


1

Non mi piace l'esempio no. 1, a causa del suo nome generico.

conditionMetnon sembra essere generico, quindi rappresenta una condizione specifica? Piace

isAdult () = { 
  age >= 18 
}

Questo andrebbe bene. È una differenza semantica, mentre

isAtLeast18 () { age >= 18; } 

non andrebbe bene per me.

Forse viene spesso utilizzato e può essere soggetto a modifiche successive:

getPreferredIcecream () { return List ("banana", "choclate", "vanilla", "walnut") }

va anche bene. Usandolo più volte, devi solo cambiare un singolo posto, se devi - forse la panna montata sarà possibile domani.

isXYZ (Foo foo) { foo.x > 15 && foo.y < foo.x * 2 }

non è atomico e dovrebbe darti una buona opportunità di prova.

Se hai bisogno di passare una funzione, ovviamente, passa quello che ti piace e scrivi funzioni dall'aspetto stupido.

Ma in generale, vedo molte più funzioni, che sono troppo lunghe, rispetto a funzioni che sono troppo brevi.

Un'ultima parola: alcune funzioni sembrano appropriate, perché sono scritte in modo troppo dettagliato:

function lessThan (a, b) {
  if (a < b) return true else return false; 
}

Se vedi, è lo stesso di

return (a < b); 

non avrai problemi con

localLessThan = (a < b); 

invece di

localLessThan = lessThan (a, b); 

0

Non c'è codice come nessun codice!

Mantenerlo semplice e non complicare troppo le cose.

Non è essere pigro, sta facendo il tuo lavoro!


0

Sì, va bene avere una funzione di codice funzione. Nel caso di metodi come "getter", "setter", "accesors" è molto comune, come menzionato nelle risposte precedenti.

A volte, quelle brevi funzioni di "accesso" sono virtuali, perché quando vengono sostituite in sottoclassi le funzioni avranno più codice.

Se vuoi che tu funzioni non così brevemente, beh, in molte funzioni, sia globali che metodi, di solito uso una variabile "risultato" (stile pascal) invece di un ritorno diretto, è molto utile quando si usa un debugger.

function int CalculateSomething() {
  int Result = -1;

   // more code, maybe, maybe not

  return Result;
}

0

Troppo breve non è mai un problema. Alcuni motivi per le funzioni brevi sono:

riutilizzabilità

Ad esempio, se si dispone di una funzione, come un metodo set, è possibile affermarlo per assicurarsi che i parametri siano validi. Questo controllo deve essere eseguito ovunque sia impostata la variabile.

manutenibilità

Potresti usare alcune affermazioni che pensi possano cambiare in futuro. Ad esempio, ora mostri un simbolo in una colonna, ma in seguito potrebbe cambiare in qualcos'altro (o persino in un segnale acustico).

Uniformità

Stai usando ad esempio il modello di facciata e l'unica cosa che una funzione fa è passare esattamente la funzione a un'altra senza cambiare argomento.


0

Quando dai un nome a una sezione di codice, è essenzialmente per dargli un nome . Questo può essere per una delle diverse ragioni, ma il punto cruciale è se puoi dargli un nome significativo che si aggiunge al tuo programma. Nomi come "addOneToCounter" non aggiungerebbero nulla, ma lo conditionMet()farebbero.

Se hai bisogno di una regola per scoprire se lo snippet è troppo corto o troppo lungo, prendi in considerazione quanto tempo impieghi a trovare un nome significativo per lo snippet. Se non riesci a farlo entro un ragionevole lasso di tempo, lo snippet non ha dimensioni adeguate.


0

No, ma può essere troppo conciso.

Ricorda: il codice viene scritto una volta, ma letto più volte.

Non scrivere codice per il compilatore. Scrivilo per i futuri sviluppatori che dovranno mantenere il tuo codice.


-1

Sì cara, la funzione potrebbe essere sempre più piccola e se è buona o cattiva dipende dal linguaggio / quadro che stai utilizzando.

A mio avviso, lavoro principalmente su tecnologie front-end, le piccole funzioni sono principalmente utilizzate come funzioni di supporto che saranno costrette a usarle molto quando si lavora con piccoli filtri e si utilizza la stessa logica in tutta l'applicazione. Se la tua applicazione ha troppe logiche comuni, allora ci saranno un sacco di piccole funzioni.

Ma in un'applicazione in cui non hai una logica comune non sarai obbligato a creare piccole funzioni ma puoi suddividere il codice in segmenti in cui diventa facile da gestire e comprendere.

In generale, suddividere il tuo enorme codice in una piccola funzione è un ottimo approccio. Nei quadri e nei linguaggi moderni sarai obbligato a farlo, ad es

data => initScroll(data)

è una funzione anonima in ES 2017 JavaScript e Typescript

getMarketSegments() {
 this.marketService.getAllSegments(this.project.id)
  .subscribe(data => this.segments = data, error => console.log(error.toString()));
}

nel codice sopra puoi vedere la dichiarazione di 3 funzioni e 2 chiamate di funzione, questa è una semplice chiamata di servizio in Angular 4 con Typescript. Puoi pensarlo come le tue esigenze

([] 0)
([x] 1)
([x y] 2)

Quanto sopra sono 3 funzioni anonime in linguaggio clojure

(def hello (fn [] "Hello world"))

Quella sopra è una dichiarazione funzionale in clojure

Quindi sì, le FUNZIONI possono essere più piccole ma se sono buone o cattive se hai funzioni come:

incrementNumber(numb) { return ++numb; }

Beh, non è una buona pratica farlo, ma cosa succede se si utilizza questa funzione in un tag HTML come facciamo in Angular Framework se non ci fosse supporto per l'incremento o il decremento nei modelli HTML angolari, questa sarebbe stata la soluzione per me.

Facciamo un altro esempio

insertInArray(array, newKey) {
 if (!array.includes(newKey)) {
   array.push(newKey);
 }
}

L'esempio sopra è d'obbligo quando si gioca quando si trovano array all'interno di modelli HTML angolari. Quindi a volte dovrai creare piccole funzioni


-2

Non sono d'accordo con quasi la risposta data in questo momento.

Recentemente ho trovato un collega che scrive tutti i membri della classe come il seguente:

 void setProperty(int value){ mValue=value; }
 int getProperty() const { return (mValue); }

Questo potrebbe essere un buon codice in casi sporadici, ma sicuramente non se si definiscono molte classi con molte e molte proprietà. Non voglio dire, con questo, che metodi come quelli sopra non devono essere scritti. Ma, se finisci per scrivere la maggior parte del codice come "wrapper" della logica reale, c'è qualcosa che non va.

Probabilmente al programmatore manca la logica generale, la paura dei cambiamenti futuri e del refactoring del codice.

La definizione dell'interfaccia è perché un bisogno reale; in effetti se è necessario impostare e ottenere una proprietà semplice (senza molta logica, il che rende il membro più breve) dovrebbe essere possibile. Ma se il reale bisogno potesse essere analizzato in modo diverso, perché non definire un'interfaccia più intuitiva?

Per rispondere davvero alla domanda, ovviamente non lo è, e la ragione è molto ovvia: il metodo / proprietà / quant'altro deve essere definito per ciò di cui ha bisogno. Anche una funzione virtuale vuota ha un motivo per esistere.


6
C'è una buona ragione per aggiungere metodi di accesso / mutatore, di cui si accenna sotto la "paura del futuro ... refactoring". Ma hai anche ragione sul fatto che non aggiunge valore al codice. Né riducendo le dimensioni (a livello locale o globale) o aumentando la leggibilità. Nella mia mente, ciò parla di un linguaggio scadente nella progettazione di Java e JavaBeans. Questa è un'area (tra le tante) in cui C # ha migliorato con successo la lingua per affrontare entrambi i problemi con la sintassi automatica delle proprietà . Come programmatore Java, sono d'accordo con il tuo stile grezzo per le classi di base strutt-like.
Anm

1
Le funzioni getter / setter sono buone anche se tutto ciò che fanno in questo momento è leggere o scrivere una variabile. In pratica, puoi immaginare uno scenario in cui in seguito decidi di stampare un valore sullo schermo ogni volta che il campo cambia o di verificare se quel valore è valido o meno. (Forse è un denominatore per una frazione, e vuoi controllare per assicurarti che non sia zero.)
Rei Miyasaka,

2
Getter e setter sono terribili, nonostante il loro uso valido. Se è necessario usarli, lo considero un fallimento della lingua.
Carson Myers,

@Rei: perché una classe esterna dovrebbe verificare il valore dei denominatori? Ciò dovrebbe essere fatto dalla funzione divide () della classe Fraction o la classe Fraction dovrebbe fornire un isDivisible () per verificare la presenza di denominatori null. Avere bisogno di getter / setter è di solito un odore di codice che la tua classe ha un alto accoppiamento e / o bassa coesione (cioè cattivo).
Lie Ryan,

@ Cosa? Non ho mai detto che una classe esterna dovrebbe essere usata per controllare i denominatori. Sto dicendo che una classe esterna potrebbe impostare un denominatore su 0 per caso. Lo scopo di avere controlli di validità nei setter è di incoraggiare eventuali bug nel codice del consumatore che possono essere trovati prima. Fornire una funzione isDivisible () che potrebbe essere chiamata o no potrebbe anche non funzionare a tal fine. E in che modo esattamente i getter / setter che necessitano indicano che c'è un alto accoppiamento?
Rei Miyasaka,
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.