Previous Entry Поделиться Next Entry
сеттеры и геттеры
artem_talipov
Пытаюсь более специфицировать понятия.


Сеттер это метод класса, который задаёт значение инкапсулированного поля с предварительной проверкой.

Геттер это метод класса, который возвращает значение инкапсулированного поля.

А вот тут-то и начинаются приколы. Сеттеры и геттеры это попытка заменить свойства. Я думаю, что их массированному введению поспособствавал язык C++. Который лишен свойств класса.

Делать поля класса публичными, это нарушает принцыпы объектно-ориентированного программирования. Я считаю, что модификатор доступа public, для динамических полей класса должен быть запрещён. Поскольку, в публичное поле можно записать значение, которое нарушит логику работы объекта. В идиале надо использовать свойства, которые и будут проверять присваиваемые значения.

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

Чтобы отличать сеттер, от обычного метода используеться префикс "set_", а для геттера префикс "get_".
И опять C++, нарушил это негласное соглашение, полностью отказавшись от префиксов. Я согласен, что так получаеться короче, а перегрузка позволяет использовать подобный синтаксис.

Но! Смысл различий обычных методов и сеттеров с геттерами, размылся. Уже непонятно, когда и что надо использовать.

Я ранее уже предлагал реализацию свойств на языке C++. Так что о них сейчас не буду распространяться.

Хочу определить границу, которая будет отличать метод от сеттеров и геттеров.

Давайте по очереди. Сначала геттер. Для примера возьмём класс string. Метод get_length() должен возвращать длину строк. А если строки не существует, то он должен возвращать 0.


long string::get_length() const
{

// если строка пуста, то возвращает 0
if( this->is_empty() )
{
return( 0 );
}

// возвращает длину строки
return( this->i_length );
}


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


long window::get_width() const
{

// если окно не создано, то возвращает 0
if( false == this->is_create() )
{
throw system_error( GetLastError() );
}

// получает позиции окна
RECT rect;
if( FALSE == GetWindowRect( this->i_handle, &rect ) )
{
// произошла ошибка
return( 0 );
}

// возвращает ширину окна
return( rect.left - rect.right );
}


Как вы видете, свойства в классе нету. Его приходится получать из функции, а потом ещё и дополнительно получать. Это так называемый псевдо геттер. Но это не делает такой геттер ущербным. Он имеет право на существование.


На очереди у нас сеттер, и вернёмся к строке. По аналогии с предыдущим , в паре get_length() нужен set_length(). О! Это сразу я затронул больной вопрос. Он не столько програмный, сколько филосовский. Ведь это не просто изменяется поле, а меняется длина строки.
А почему бы и правда не менять длину строки? Кто мешает? Мешает только размер выделенной памяти. Перемщать и заново выделять память, это более сложная задача, которая уже затронет всю строку, а не только конкретное поле i_length. А значит изменять размер выделенной памяти не будем.


void string::set_length( long value )
{

// выходит, если строка пуста
if( this->is_empty() )
{
return;
}

// если заданное значение превышает размер выделенной памяти
if( value > this->get_size() )
{
// то задаётся максимально допустимый размер
this->i_length = this->get_size();
return;
}

// устанавливается заданный размер
this->i_length = value;
}


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

Ха-эм, а я в примере упомянул метод get_size().


long string::get_size() const
{

// если строка пуста, то возвращает 0
if( this->is_empty() )
{
return( 0 );
}

// возвращает размер зарезервированной памяти строки
return( this->i_size );
}


И в пару ему нужен соответствующий сеттер. Но какой? В рамках, вышеназванных принцыпов, сеттер аналогичный set_length, не допустим. Ведь в этом случае, придётся изменять размер зарезервированной памяти!
Ну что же, раз нельзя, так и не будем его делать. Нефиг извращатся.

А вот метод resize(), который изменит размер строки, вполне можно создать, никто это не запрещает.


void string::resize( long size )
{

// выходит, если строка пуста
if( this->is_empty() )
{
return;
}

// резервирует блок памяти для новой строки
elem_ptr buff = new elem_type[ size ];

// вычисляет длину сохраняемого текста
long len = ( size < this->i_length ) ? size : this->i_length;

// копирует текст
for( long i = 0; i < len; i++ )
{
buff[i] = this->i_value[i];
}

// очищает старый блок памяти
this->clear();

// задаёт новые поля
this->i_value = buf;
this->i_size = size;
this->i_length = len;
}


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

Вот она, та самая граница, которая мне была нужна.
Геттер получает некое значение из объекта, не влияя тем самым на объект.
Сеттер только изменяет указанную характеристику объекта не изменяя других характеристик.
Всё остальное должно считаться методами.

Справедливо и обратное, если метод работает как геттер или сеттер, то и оформлять его нужно соответствующе, с префиксами, и подумав над парным геттером или сеттером.


?

Log in