getters e setters estilo
-
05-07-2019 - |
Pergunta
(Deixando de lado a questão de que você deve tê-los em tudo.)
Eu sempre preferiu função apenas uso sobrecarga para dar-lhe o mesmo nome para ambos getter e setters.
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, eu estou correto, mas eu me perguntava se os escritores biblioteca tinha nenhuma boa razão?
Solução
Eu preferiria as versões get / set, porque é mais clara quanto ao que está acontecendo. Se eu taxa de serra () e taxa (10), como eu sei que a taxa (10) não está simplesmente usando 10 no cálculo para retornar a taxa? Eu não, então agora eu tenho para iniciar a pesquisa para descobrir o que está acontecendo. Um nome de função única deve fazer uma coisa, não duas coisas opostas.
Além disso, como os outros têm para fora pontas, alguns preferem omitir o 'ficar' e deixar o 'set', i.,
int Rate( );
void SetRate( int value );
Esta convenção é bastante clara, bem, eu não teria qualquer problema ao ler isso.
Outras dicas
Eu sempre preferiu omitir o 'get' em meus getters, como você faz, com rate()
vez de getRate()
. Mas a sobrecarga para o setter não parece ser uma idéia muito boa para mim, já que o nome rate
não transmitir que o objeto está sendo mutado. Considere o seguinte:
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?
Como cerca int rate();
e void setRate(int value);
? Isto tem a virtude de não ter duas funções com o mesmo nome fazendo coisas diferentes, e ainda permite period() * rate()
.
Alguns anos atrás, eu teria concordado completamente. Mais recentemente, uma dúvida começou a fazer o seu caminho, porque isso faz tomar o endereço de um getter ou setter ambígua. Com ferramentas como tr1 :: bind, este é realmente irritante.
Por exemplo:
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));
);
Deixando de lado a questão de que você deve tê-los em tudo; -)
Eu vou em frente e mencionar esta deve ser uma questão wiki comunidade.
Quando eu comecei a aprender C ++ Olhei para guias de estilo, e Google era bom para alguns pontos:
- Métodos em maiúsculas (que é apenas mais bonita).
- getters clara e quanto minúsculas (
rate
). - setters explicitamente e minúsculas (
setRate
).
Ser conciso é importante, mas não à custa de ser incompleta ou enganosa. Por essa razão, eu prefiro getFoo () e setFoo () para Foo () e Foo (int foo).
Existem vários níveis para "ficar" e "Setting"
- Eu uso get e set de "fast" operações.
- Se algo vai demorar mais tempo para executar, então ele vai muitas vezes ser um Calc, como esses nomes sugerem que algum trabalho tem que ser feito para recuperar o resultado.
- Para operações mais longas, você começa a entrar em prefixos como Load / Save, Consulta / loja, Read / Write, Pesquisa / Encontrar etc.
Assim GET / SET pode ser atribuído um significado útil, e ser parte de uma estratégia de nomenclatura consistente maior.
Enquanto o comentário de Ed é verdade, eu prefiro propriedades reais sobre o setter / getter antipattern. Quando 1 / 3rd dos métodos em seu domínio gráfico são métodos fictícios que foram gerados pelo eclipse, há algo errado.
Sem propriedades de primeira classe, no entanto, acredito que o antipattern faz mais sentido.
Além disso, torna a conclusão de código mais fácil.
obj.set (control shift space)
para setters
obj.get (control shift space)
para getters
Pessoalmente, acho que getters e setters encontrados em pares são um cheiro de código transitadas de línguas "visual" e suas "propriedades". Em um "bom" classe, os membros de dados são writeonly ou somente leitura, mas não de leitura / gravação.
Eu acho que a causa mais comum de getters e setters não está carregando o modelo de objeto profundidade suficiente. No seu exemplo, porque é que ser total passou o período ea taxa? Eles não são membros da classe? Então você só deve ser definir o período ea taxa e você só deve estar recebendo um total.
Há provavelmente exceções, mas eu odeio olhando para uma classe e encontrar "getX / setX, getY / setY, etc. etc." Parece apenas não foi o suficiente pensado em como deve ser utilizada a classe e sim o autor fez a classe fácil de obter para os dados para que ele não tem que considerar como a classe deve ser usado.
Naturalmente estou correto.
Outra questão que ninguém tenha mencionado é o caso de sobrecarga de funções. Veja este exemplo (artificial 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
};
Sem essa cláusula using
, os usuários de Contractor
não pode consultar o salário por causa da sobrecarga. Recentemente adicionado -Woverloaded-virtual
ao conjunto de alerta de um trabalho de projecto I, e eis que, este mostrou-se por todo o lugar.
Eu impor a convenção em que um método deve ser sempre um verbo e uma classe deve sempre ser um substantivo (exceto para functors, por razões óbvias). Nesse caso, um get / set prefixo deve ser utilizado para a consistência. Dito isto, eu também concordo inteiramente com Ed Swangren. Isto resume a mim como usar esses prefixos um acéfalo.
Eu prefiro evitar os obter e definir rótulos, a informação não é necessário para o compilador para fazer seu trabalho para a maioria dessas propriedades simples.
você pode ter problemas:
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
Se o seu getter é simplesmente rate()
, o compilador iria reclamar que a sua redefinição do seu outro símbolo rate
, desde que você deu seu campo um bom nome significativo assim. Nesse caso, você precisa fazer alguma coisa boba como nome o seu _rate
membro ou alguma outra abordagem semelhante. Eu, pessoalmente, odeio ver / digitando essas sublinhados, por isso, tendem a ir com a abordagem getRate()
.
Esta é, obviamente, subjetiva e isso só acontece de ser a minha preferência pessoal.