Как стать автором
Обновить
1046.23
OTUS
Цифровые навыки от ведущих экспертов

Сеттер или геттер-ссылка — как сделать правильный выбор?

Время на прочтение4 мин
Количество просмотров6.7K
Автор оригинала: belaycpp.com

Контекст

Когда вы создаете класс, вам часто приходится реализовывать методы доступа к одному или нескольким атрибутам этого класса для того, чтобы можно было редактировать их.

Сделать это можно двумя способами:

  •  С помощью сеттера, метода, который принимает новое значение атрибута в качестве аргумента.

  • С помощью геттера-ссылки (reference-getter), метода, который возвращает ссылку на сам атрибут.

Вот небольшой пример, показывающий, как с помощью двух этих методов получить доступ к полю bar.

class Foo {
    int m_bar;
 
public:
    //Сеттер
    void set_bar(int bar) {
        m_bar = bar;
    }
//Геттер-ссылка
int & get_bar() {
    return m_bar;
}

};
int main() {
    Foo foo;
//Редактирование через сеттер
foo.set_bar(42);

//Редактирование с помощью геттер-ссылки
foo.get_bar() = 84;

return 0;

}

Некоторые могут поспорить со мной, заявив что для этого есть и другие методы, но я остаюсь верен убеждению, что это всего лишь вариации сеттера или геттер-ссылки.

Сеттер

Сеттер по отношению к классу является интерфейсом только для записи (write-only). Вы указываете значение, и соответственно обновляете класс.

Зачастую он более или менее напрямую обновляет атрибут, копируя/перемещая(move) предоставленные вами данные.

Примеры

// Самый примитивный сеттер
void set_foo(int foo) {
   m_foo = foo;
}
// Сеттер, который делает проверку перед присваиванием
void set_foo(Foo foo) {
    if (foo.is_valid())
        m_foo = foo;
}
// move-сеттер
void set_big_foo(BigFoo && big_foo) {
    m_big_foo = std::forward<BigFoo>(big_foo);
}

Геттер-ссылка

Геттер-ссылка (reference-getter) представляет собой метод, который возвращает ссылку на атрибут, что дает непосредственный доступ к нему, в том числе предоставляя возможность его редактирования.

Этот метод особенно полезен для атрибутов-объектов для того, чтобы вы могли вызывать неконстантные методы непосредственно на них.

Примеры

// Here is the implementation of the reference-getter
Foo & MyClass::get_foo() {
    return m_foo;
}
// ...
// Used to edit an attribute
myClass.getFoo().bar = 42;
// Used to call a non-const method
myClass.getFoo().udpate();

Какой метод выбрать?

Сделать выбор станет довольно просто, как только вы поймете разницу между ними.

Когда вам нужно пересоздать данные и поместить их на место уже существующих, вам пригодится сеттер. Он также подходит для редактирования простых данных (целые числа, значения чисел с плавающей запятой, указатели и т. д.) или если вам нужно подставить полностью новое значение. Еще один вариант использования сеттеров: когда вы намеренно хотите дать пользователю возможность только редактировать данные, но не читать.

Геттер-ссылка вам пригодится для редактирования данных атрибута (а не атрибута целиком). Часто нам необходимо отредактировать только часть атрибута или вызвать для них неконстантный метод.

Другими словами, сеттер заменяет атрибут, а геттер-ссылка редактирует атрибут.

Пример

Рассмотрим следующий код:

#include <vector>
using namespace std;
struct Item
{
    bool validity;
    int value;
};
class Foo
{
public:
    Foo(size_t size) :
        m_max_size(size),
        m_data(size, {true, 0})
    {}
void set_max_size(size_t max_size) {
    m_max_size = max_size;
}

Item &amp; get_item(size_t index) {
    return m_data.at(index);
}

size_t get_data_size() const {
    return m_data.size();
}

private:
    bool m_max_size;
    std::vector<Item> m_data;
};
static void set_foo_size(Foo & foo, size_t new_size)
{
    foo.set_max_size(new_size);
    for (size_t i = new_size ; i < foo.get_data_size() ; ++i)
        foo.get_item(i).validity = false;
}

В коде представлен простой класс, который содержит набор данных (Item’ы). Эти данные могут быть валидными или невалидными (true - валидные, false - невалидные).

Затем мы реализуем небольшую функцию, которая изменяет размер коллекции, не удаляя никаких элементов. Элементы, выходящие за заданный размер, становятся невалидными.

Мы задаем значение m_max_size с помощью сеттера, так как это обычное целое число, значение которого меняется при изменении размера коллекции.

С помощью геттер-ссылки мы можем получить доступ к каждому Item‘у из m_data, так как нам не всегда требуется полностью удалять item, иногда нам необходимо просто отредактировать его часть.

Альтернатива

Мы могли бы редактировать валидность, используя более специфичный сеттер, например:

class Foo {
    // ...

    void set_item_validity(size_t index, bool validity) {
            m_data.at(index).validity = validity;
    }

    // ...

};

Сделав так, мы бы потеряли возможность редактировать value  Item,поэтому это решение полностью зависит от деталей вашей реализации.

Однако, пожалуйста, помните, что писать сеттеры и для value и для validity является плохой практикой. Делать это в корзине данных с двумя атрибутами вряд ли будет правильным решением, потому что как только ваша реализация начнет расти, ваша кодовая база будет переполнена бесполезными аксессорами. Вам нужен полный доступ? Так и реализуйте полный доступ.

Заключение

Многие из вас посчитают эту тему тривиальной, но многие разработчики все еще путаются, когда следует использовать сеттер, а когда геттер-ссылку. Будьте внимательны.


Материал подготовлен в рамках специализации «C++ Developer».

Если вам интересно узнать подробнее о формате обучения и программе, познакомиться с преподавателем специализации — приглашаем на день открытых дверей онлайн. Регистрация здесь.

Теги:
Хабы:
Всего голосов 12: ↑7 и ↓5+2
Комментарии7

Публикации

Информация

Сайт
otus.ru
Дата регистрации
Дата основания
Численность
101–200 человек
Местоположение
Россия
Представитель
OTUS