+1

Длинный список параметров -> Передача всего объекта

Андрей Ильичёв 4 years ago updated by Igor 3 years ago 2

Добрый вечер,

Уже не в первый раз вижу подобный совет (см аттач),
С одной стороны это хорошо, с другой стороны не стоит забывать про мутабельность объектов. Передаваемый объект какого-то класса (тем более! если это this) может быть незащищён от изменений, а в большинстве случаев так и есть, т.о. метод, в который передаётся весь объект целиком может произвести какие угодно изменения внутри этого объекта. По возвращении потока исполнения кода обратно в метод, откуда был передан объект целиком, данный объект уже может иметь нежелательные изменения.

В одном из других примеров ранее я видел также похожий совет, но только с конструктором класса, в который из какого-то метода стороннего класса в качестве аргумента передаётся this. Это, конечно, тоже хорошо, но не стоит забывать, например, про c++, в котором может сыграть злую шутку конструктор копирования, вызывающий, например, тот же самый метод.

Решение от языка к языку может быть разным, в скриптовых можно как вариант либо делать теневую копию, либо передавать прототипы на геттерах, либо что-то другое, а в том же C#/C++ можно у целевого класса сделать метод, возвращающий объект уже другого типа (readonly) или откопированный объект. Но стоит ли игра свеч, если нужно так много извёртываться (помимо того ещё и раздувать память), если зачастую быстрее и лаконичнее будет вытащить все поля из объекта и передать их как в примере слева? Тем более, если эти поля содержат примитивы, которые по определению в большинстве языков иммутабельны (rvalue, или как угодно).

Пы.Сы. Разумеется, с функциями GetLow() и GetHigh() много делов не наделаешь, но скорее всего у объекта с названием "daysTempRange" есть ещё и методы вида SetLow() и SetHigh() :)

Много новичков, которые не знают об особенностях конкретного языка, могут наткнуться на эту граблю, так что я думаю, что стоит как минимум упомянуть про подобный анти-пример и с осторожностью применять этот совет, так как конкретно он мне встретился уже 3й (или даже 4й) раз.

Screenshot 2021-01-03 at 01.52.13.png

Спасибо!

+2

Вся эта проблема, по крайней мере в С++, не является проблемой при соблюдении const-чистоты. Если класс у нас определен как

class TempRange {
public:
    double get_low() const { /* ... */ }
    double get_high() const { /* ... */ }
    double set_low() { /* ... */ }
    double set_high() { /* ... */ }
};

И принимающий метод будет выглядеть как-то так

bool within_range(const TempRange& tempRange) { /* ... */ }

То не возникнет проблем ни с лишним выделением памяти, ни с иммутабельностью/мутабельностью этого самого объекта. Все упирается в грамотное использование возможностей языка, кратко говоря.

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