Геттеры и сеттеры
(Оставляя в стороне вопрос о том, должны ли вы иметь их вообще.)
Я всегда предпочитал просто использовать перегрузку функций, чтобы дать вам одно и то же имя для getter и seters.
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() );
Естественно, я прав, но я задавался вопросом, есть ли у писателей библиотеки какие-то веские причины?
Ответы
Ответ 1
Я бы предпочел получить/установить версии, потому что более ясно, что происходит. Если я видел rate() и rate (10), откуда я знаю, что скорость (10) не просто использует 10 в вычислении для возврата ставки? Я этого не делаю, поэтому теперь я должен начать поиск, чтобы выяснить, что происходит. Одно имя функции должно делать одно, а не две противоположные вещи.
Кроме того, как отмечали другие, некоторые предпочитают опускать "get" и оставлять "set", т.е.
int Rate( );
void SetRate( int value );
Это соглашение также довольно ясно, я бы не имел никаких проблем с чтением этого.
Ответ 2
Как насчет int rate();
и void setRate(int value);
? Это имеет свойство не иметь двух функций одного и того же имени, делающих разные вещи, и до сих пор позволяет period() * rate()
.
Ответ 3
Я всегда предпочитал пропускать "get" на своих геттерах, как и вы, с rate()
вместо getRate()
. Но перегрузка для сеттера не кажется мне очень хорошей идеей, так как имя rate
не сообщает, что объект мутируется. Рассмотрим:
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?
Ответ 4
Несколько лет назад я бы полностью согласился. Совсем недавно возникло сомнение, потому что это делает двусмысленный адрес геттера или сеттера. С такими инструментами, как tr1:: bind, это действительно раздражает.
Например:
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));
);
Оставляя в стороне вопрос о том, должны ли вы иметь их вообще, -)
Ответ 5
Я расскажу, что это должен быть вопрос о вики сообщества.
Когда я начал изучать С++, я искал руководства по стилям, и Google был хорош для некоторых моментов:
- Способы в верхнем регистре (это только красивее).
- getters явно и lowecase (
rate
).
- устанавливает явно и строчные буквы (
setRate
).
Ответ 6
Быть кратким важно, но не ценой неполного или вводящего в заблуждение. По этой причине я предпочитаю GetFoo() и SetFoo() для Foo() и Foo (int foo).
Ответ 7
Существует несколько уровней "Получение" и "Настройка"
- Я использую Get и Set для "быстрых" операций.
- Если что-то займет больше времени для выполнения, то это часто будет Calc, так как эти имена подразумевают, что для получения результата нужно выполнить некоторую работу.
- Для более длительных операций вы начинаете получать префиксы, такие как Load/Save, Query/Store, Read/Write, Search/Find и т.д.
Таким образом, Get/Set можно приписать полезное значение и стать частью более крупной и последовательной стратегии именования.
Ответ 8
В то время как комментарий Ed верен, я предпочитаю фактические свойства над antipattern setter/getter. Когда 1/3 из методов на вашем графике домена являются фиктивными методами, которые были сгенерированы eclipse, что-то не так.
Без свойств первого класса, однако, я считаю, что антипаттерн имеет наибольший смысл.
Кроме того, это облегчает выполнение кода.
obj.set (control shift space)
для сеттеров
obj.get (control shift space)
для геттеров
Ответ 9
Лично я считаю, что геттеры и сеттеры, найденные в парах, представляют собой запах кода, переносимый с "визуальных" языков и их "свойств". В "хорошем" классе члены данных записываются только или только для чтения, но не для чтения/записи.
Я думаю, что самая распространенная причина геттеров и сеттеров не слишком сильно переносит объектную модель. В вашем примере, почему общее время передается период и курс? Разве они не являются членами класса? Таким образом, вы должны устанавливать только период и скорость, и вы должны получать всего.
Вероятно, есть исключения, но я просто ненавижу смотреть на класс и нахожу "getX/setX, getY/setY и т.д. и т.д.". Кажется, что недостаточно было подумать о том, как класс следует использовать, и, скорее, автор сделал класс EASY доступным для данных, поэтому ему не пришлось бы учитывать, как использовать класс.
Естественно, я прав.
Ответ 10
Другая проблема, о которой никто не упомянул, относится к перегрузке функций. Возьмите этот (надуманный и неполный) пример:
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
};
Без этого предложения using
пользователи Contractor
не могут запрашивать зарплату из-за перегрузки. Недавно я добавил -Woverloaded-virtual
в предупреждающий набор проекта, над которым я работаю, и вот и вот, это появилось повсюду.
Ответ 11
Я применяю соглашение, в котором метод всегда должен быть глаголом, а класс всегда должен быть существительным (за исключением функторов, по понятным причинам). В этом случае префикс get/set должен использоваться для согласованности. Тем не менее, я также полностью согласен с Эд Свангрен. Это сумма для меня, как использование этих префиксов без проблем.
Ответ 12
Я предпочитаю избегать меток get и set, информация не нужна компилятору для выполнения этой работы для большинства этих простых свойств.
у вас могут быть проблемы:
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
Ответ 13
Если ваш получатель просто rate()
, ваш компилятор будет жаловаться на то, что его переопределение вашего другого символа rate
, если вы дали своему полю такое содержательное имя. В этом случае вам нужно сделать что-то глупое, как имя вашего члена _rate
или какой-либо другой подобный подход. Я лично ненавижу видеть/печатать эти символы подчеркивания, поэтому, как правило, придерживаюсь подхода getRate()
.
Это, очевидно, субъективно, и это просто мое личное предпочтение.