Подтвердить что ты не робот

Геттеры и сеттеры

(Оставляя в стороне вопрос о том, должны ли вы иметь их вообще.)

Я всегда предпочитал просто использовать перегрузку функций, чтобы дать вам одно и то же имя для 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() );

Естественно, я прав, но я задавался вопросом, есть ли у писателей библиотеки какие-то веские причины?

4b9b3361

Ответ 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().

Это, очевидно, субъективно, и это просто мое личное предпочтение.