2009-10-22 18 views
20

(lasciando da parte la questione di se li hanno affatto).getter e setter stile

ho sempre preferito utilizzare solo la funzione sovraccarico per darvi lo stesso nome sia per getter e setter.

int rate() { return _rate; }  
void rate(int value) { _rate = value; } 

// instead of  
int getRate() { return _rate; }  
void setRate(int value) { _rate = value; } 

// mainly because it allows me to write the much cleaner  
total(period() * rate());  
// instead of  
setTotal(getPeriod() * getRate()); 

Naturalmente, ho ragione, ma mi chiedevo se gli scrittori della biblioteca avessero una buona ragione?

+26

"Naturalmente, ho ragione" È piuttosto divertente, spero che fosse inteso come uno scherzo. –

risposta

30

Preferirei le versioni get/set perché è più chiaro su cosa sta succedendo. Se ho visto rate() e rate (10), come faccio a sapere che rate (10) non sta semplicemente usando 10 nel calcolo per restituire il rate? Io no, quindi ora devo iniziare a cercare per capire cosa sta succedendo. Un nome di una singola funzione dovrebbe fare una cosa, non due cose opposte.

Inoltre, come altri hanno fatto notare, alcuni preferiscono omettere il 'get' e lasciare il 'set', vale a dire,

int Rate(); 
void SetRate(int value); 

Tale convenzione è abbastanza chiaro così, non avrei alcun problema a leggerlo.

+2

Buon punto. Supponete che la persona che usa il vostro codice non sia solo un maniaco omicida che sa dove vivi, ma è anche un po 'confuso! –

1

Mentre il commento di Ed è vero, preferisco le proprietà effettive al setter/getter antipattern. Quando 1/3 dei metodi nel tuo dominio grafico sono metodi fittizi che sono stati generati da Eclipse, c'è qualcosa di sbagliato.

Senza proprietà di prima classe, tuttavia, credo che l'antipattern abbia più senso.

Inoltre, facilita il completamento del codice.

obj.set (control shift space) per setter
obj.get (control shift space) per getter

+0

Perché è un "antipattern" quando le proprietà di prima classe sono semplicemente zucchero sintattico per la stessa cosa? il concetto è lo stesso, è semplicemente l'implementazione che differisce. –

+0

È un antipattern nel senso che potrebbe essere un solo rivestimento. proprietà privata int value; // ora funziona con i contenitori IoC; Sìì. "Ripeto 30 righe di codice nella parte superiore di tutte le mie funzioni.Quanto è un antipattern? Il codice funziona!" –

+0

Penso che significhi avere getter/setter è un modello anti-che non è necessariamente vero - vedi il mio commento a jmucchiello –

5

ho sempre preferito omettere il 'get' sul mio getter, come si fa, con rate() invece di getRate(). Ma sovraccaricare il setter non mi sembra una buona idea, dal momento che il nome rate non comunica che l'oggetto è stato mutato. Considerate:

total(period() * rate()); // awesome, very clear 

rate(20); // Looks like it computes a rate, using '20'...but for what? And why ignore the return value? 
+0

questo è lo stile Qt e java. http://qt.gitorious.org/qt/pages/ApiDesignPrinciples ---> goto "the art of naming" –

6

Come su int rate(); e void setRate(int value);? Questo ha il merito di non avere due funzioni con lo stesso nome facendo cose diverse, e comunque permette di period() * rate().

+1

Probabilmente causerebbe confusione con le persone che cercano getXXX –

+0

questo è lo stile Qt e java. http://qt.gitorious.org/qt/pages/ApiDesignPrinciples ---> goto "the art of naming" –

5

Alcuni anni fa, avrei acconsentito completamente. Più recentemente, un dubbio ha iniziato a farsi strada, perché ciò rende ambiguo il discorso di un getter o setter. Con strumenti come tr1 :: bind, questo è davvero fastidioso.

Ad esempio:

struct A 
{ 
    void Foo(int); 
    int Foo()const; 
}; 

std::vector<A> v = ....; 
std::vector<int> foos; 
// Extract Foo 
std::transform(
    v.begin(), v.end(), 
    std::back_inserter(foos), 
    //Ambiguous 
    // std::tr1::bind(&A::Foo) 
    //must write this instead. Yuck! 
    std::tr1::bind(static_cast<int(Foo::*)()>(&A::Foo)); 
); 

Lasciando da parte la questione della loro dovrebbe avete affatto ;-)

+0

bind() e ancor peggio bind2nd() sono le cose che mi rendono la cosa C++ è irrimediabilmente rotta. Non ci si può ragionevolmente aspettare che nessun essere umano analizzi, e tanto meno scriva, quella riga di codice correttamente! –

+1

Buon punto. Il sovraccarico è bello da solo, ma interferisce quando si desidera iniziare a prendere gli indirizzi di funzione. - @mgb: non sottovalutare gli altri umani. Si potrebbe anche usare 'std :: mem_fun_ref', ma ancora a causa degli overload, i tipi devono essere specificati:' std :: mem_fun_ref (& A :: Foo) '. – UncleBens

4

io vado avanti e citato questo dovrebbe essere una questione della comunità wiki.

Quando ho iniziato a imparare C++ ho cercato guide di stile, e Google era buono per alcuni punti:

  • Methods in maiuscolo (è solo più bella).
  • getter chiari e minuscoli (rate).
  • setter esplicitamente e minuscole (setRate).
+0

ok - era solo una specie di pausa caffè inattiva. –

2

Essere concisi è importante, ma non a costo di essere incompleto o fuorviante. Per questo motivo, preferisco GetFoo() e SetFoo() a Foo() e Foo (int foo).

1

Personalmente, penso che getter e setter si trovano in coppie sono un odore di codice riportati dal lingue "visivi" e le loro "proprietà". In una classe "buona", i membri di dati sono writeonly o readonly ma non di lettura/scrittura.

Penso che la causa più comune di getter e setter non sta portando il modello a oggetti abbastanza profonda. Nel tuo esempio, perché viene passato il totale e il tasso? Non sono membri della classe? Quindi dovresti impostare solo il periodo e il tasso e dovresti ottenere solo un totale.

Probabilmente ci sono delle eccezioni, ma ho solo odio guardando una classe e di trovare "GetX/setX, Gety/Sety, ecc ecc" Sembra solo che non ci fosse abbastanza pensiero su come la classe DOVREBBE essere usata e piuttosto l'autore ha reso la classe EASY per ottenere i dati in modo che non avrebbe dovuto considerare come la classe dovrebbe essere utilizzata.

Naturalmente ho ragione.

+0

Pensa a un tipo di punto 3D. Avrà molte funzioni interne per fare varie cose di matematica, ma alla fine avrà bisogno di tutte le 6 funzioni get/set x/y/z. –

+0

@mgb: personalmente non credo che un tipo di punto 3d debba nascondere i membri in primo luogo (eccetto forse perché si potrebbe voler usare un array come rappresentazione interna). – UncleBens

2

Ci sono diversi livelli di "ricevere" e "Impostazione"

  • Io uso Get e Set per le operazioni di "veloci".
  • Se qualcosa ci vorrà più tempo per l'esecuzione, allora sarà spesso una Calc, come questi nomi implica che un certo lavoro deve essere fatto per recuperare il risultato.
  • Per le operazioni più lunghe, si inizia a entrare in prefissi come Load/Save, Query/Store, lettura/scrittura, Ricerca/Trova ecc

Quindi get/set può essere attribuito un significato utile, ed essere parte di una strategia di denominazione più ampia e coerente.

0

Applico la convenzione in cui un metodo dovrebbe sempre essere un verbo e una classe dovrebbe sempre essere un nome (ad eccezione dei funtori, per ovvi motivi). In tal caso, deve essere utilizzato un prefisso get/set per coerenza. Detto questo, sono anche d'accordo completamente con Ed Swangren. Questo mi ha dato l'idea di usare quei prefissi un gioco da ragazzi.

1

Un altro problema che nessun altro ha menzionato è il caso di sovraccarico di funzione. Prendete questo esempio (artificioso e incompleto):

class Employee { 
    virtual int salary() { return salary_; } 
    virtual void salary(int newSalary) { salary_ = newSalary; } 
}; 

class Contractor : public Employee { 
    virtual void salary(int newSalary) { 
     validateSalaryCap(newSalary); 
     Employee::salary(newSalary); 
    } 
    using Employee::salary; // Most developers will forget this 
}; 

Senza che using clausola, gli utenti di Contractor non possono interrogare lo stipendio a causa del sovraccarico. Di recente ho aggiunto -Woverloaded-virtual al set di avvertenze di un progetto su cui lavoro, ed ecco che questo è apparso dappertutto.

+0

Non si conosce l'equivalente di -Woverloaded-virtual per MSVC? –

+1

@Greg scusa, non lo so. In realtà trovo che gli avvisi di MSVC (a partire da VC8) siano per lo più controproducenti (avviso di prestazione per la conversione tra bool e int? Struct precedentemente forward-dichiarato come classe?) Dato che costruisco su due piattaforme, di solito faccio affidamento su gcc per tutti i miei bisogni di avvertenze. – Tom

0

Preferisco evitare le etichette get e set, l'informazione non è necessaria perché il compilatore faccia il suo lavoro per la maggior parte di queste semplici proprietà.

si può avere problemi:

class Stuff { 
    void widget(int something); // 'special' setter 
    const Widget& widget(int somethingelse) const; // getter 
} 
Stuff a; 
a.widget(1); // compiler won't know which widget you mean, not enough info 
+2

Non scrivi nomi significativi per il compilatore, lo fai per l'altro programmatore che deve usare il tuo codice. – Triskeldeian

+0

Si prega di non pensare che scrivere codice breve/intelligente/conciso sia in qualche modo automaticamente migliore. Scrivi il codice in modo che tu e i tuoi coetanei sappiate cosa sta succedendo 6 mesi dopo senza strappare i capelli. – nenchev

0

Se il getter è semplicemente rate(), il compilatore si lamentava che il suo una ridefinizione del vostro altro rate simbolo, a condizione che hai dato il tuo campo di un buon nome significativo come quello. In tal caso è necessario fare qualcosa di sciocco come il nome del membro _rate o qualche altro approccio simile. Personalmente odio vedere/digitare quei caratteri di sottolineatura, quindi tendiamo ad adottare l'approccio getRate().

Questo è ovviamente soggettivo e questa è la mia preferenza personale.