По моему скромному мнению, есть три вида возвратов, которые вы должны принять во внимание:
манипулирование свойствами объекта
Первое - это манипулирование свойствами объекта. Шаблон, который вы описываете здесь, очень часто используется при манипулировании объектами. Очень типичный сценарий - использовать его вместе с фабрикой. Рассмотрим этот гипотетический призыв к созданию:
// When the object has manipulative methods:
Pizza p = PizzaFactory().create().addAnchovies().addTomatoes();
// When the factory has manipulative methods working on the
// object, IMHO more elegant from a semantic point of view:
Pizza p = PizzaFactory().create().addAnchovies().addTomatoes().getPizza();
Это позволяет быстро понять, что именно создается или как манипулировать объектом, потому что методы образуют одно читаемое человеком выражение. Это определенно приятно, но не злоупотребляйте. Практическое правило заключается в том, что это можно использовать с методами, возвращаемое значение которых вы также можете объявить как void.
Оценка свойств объекта
Вторым может быть, когда метод оценивает что-либо на объекте. Рассмотрим, например, метод car.getCurrentSpeed()
, который можно интерпретировать как сообщение объекту, запрашивающее текущую скорость и возвращающее ее. Это просто вернет значение, не слишком сложное. :)
Заставить объект делать то или иное
Третий может быть, когда метод выполняет операцию, возвращая какое-то значение, указывающее, насколько хорошо было выполнено намерение вызывающего, - но такой метод может быть затруднен:
int new_gear = 20;
if (car.gears.changeGear(new_gear)) // does that mean success or fail?
Здесь вы можете увидеть трудности при разработке метода. Должен ли он вернуть 0 в случае успеха или неудачи? Как насчет -1, если передача не может быть установлена, потому что в машине всего 5 передач? Значит ли это, что текущая передача сейчас тоже равна -1? Метод может вернуть механизм, на который он был изменен, что означает, что вам придется сравнивать аргумент, предоставленный методу, с кодом возврата. Это будет работать. С другой стороны, вы можете просто вернуть либо true, либо false для сбоя, либо false или true для сбоя. Какой из них использовать, можно определить, рассчитав, ожидаете ли вы, что вызовы этих методов скорее не пройдут, либо завершатся успешно.
По моему скромному мнению, есть способ лучше выразить семантику таких возвращаемых значений, дав им семантическое описание. Будущие разработчики, взаимодействующие с вашими объектами, будут любить вас за то, что вам не нужно искать комментарии или документацию для ваших методов:
class GearSystem {
// (...)
public:
enum GearChangeResult
{ GearChangeSuccess, NonExistingGear, MechanicalGearProblem };
GearChangeResult changeGear (int gear);
};
Таким образом, для любого программиста, который смотрит на ваш код, становится совершенно очевидным, что означает возвращаемое значение (рассмотрим: if (gears.changeGear(20) == GearSystem::GearChangeSuccess)
- гораздо яснее, что это значит, чем в примере выше)
Antipattern: ошибки в качестве кодов возврата.
Четвертую возможность для возвращаемого значения я на самом деле пропустил, потому что, на мой взгляд, это не так: когда в вашей программе есть ошибка, например логическая ошибка или ошибка, с которой нужно справиться - вы можете теоретически вернуть значение, указывающее на это. Но сегодня это делается не так часто (или не должно быть), потому что для этого есть исключения.