Я пишу много кода, как это:
int myFunction(Person* person) {
int personIsValid = !(person==NULL);
if (personIsValid) {
// do some stuff; might be lengthy
int myresult = whatever;
return myResult;
}
else {
return -1;
}
}
Это может стать довольно грязным, особенно если задействовано несколько проверок. В таких случаях я экспериментировал с альтернативными стилями, такими как этот:
int netWorth(Person* person) {
if (Person==NULL) {
return -1;
}
if (!(person->isAlive)) {
return -1;
}
int assets = person->assets;
if (assets==-1) {
return -1;
}
int liabilities = person->liabilities;
if (liabilities==-1) {
return -1;
}
return assets - liabilities;
}
Я заинтересован в комментариях о стилистическом выборе здесь. [Не беспокойтесь о деталях отдельных заявлений; меня интересует общий поток управления.]
coding-style
language-agnostic
Уильям Джокуш
источник
источник
Ответы:
Для такого рода вопросов Мартин Фаулер предложил образец спецификации :
Выше звучит немного брови (по крайней мере, для меня), но когда я попробовал это в своем коде, все прошло довольно гладко и оказалось легко реализовать и прочитать.
На мой взгляд, основная идея состоит в том, чтобы «извлечь» код, который выполняет проверки, в выделенный метод (ы) / объекты.
В вашем
netWorth
примере это может выглядеть примерно так:Ваш случай выглядит довольно простым, так что все проверки выглядят нормально, чтобы поместиться в простой список в пределах одного метода. Мне часто приходится разделять на несколько методов, чтобы лучше читать.
Я также обычно группирую / извлекаю связанные со спецификацией методы в выделенном объекте, хотя ваш случай выглядит нормально без этого.
Этот вопрос в Stack Overflow рекомендует несколько ссылок в дополнение к одной из упомянутых выше: Пример шаблона спецификации . В частности, ответы предлагают Dimecasts «Изучение шаблона спецификаций» для ознакомления с примером и упоминают статью «Спецификации», написанную Эриком Эвансом и Мартином Фаулером .
источник
Мне легче перенести валидацию в свою собственную функцию, она помогает сохранить цель других функций более чистой, поэтому ваш пример будет таким.
источник
if
вvalidPerson
? Просто вернитесьperson!=NULL && person->isAlive && person->assets !=-1 && person->liabilities != -1
вместо этого.Одна вещь, которую я видел, работает особенно хорошо - это введение уровня проверки в ваш код. Сначала у вас есть метод, который выполняет всю грязную проверку и возвращает ошибки (как
-1
в ваших примерах выше), когда что-то идет не так. Когда проверка завершена, функция вызывает другую функцию для выполнения фактической работы. Теперь этой функции не нужно выполнять все эти шаги проверки, потому что они уже должны быть выполнены. То есть рабочая функция предполагает, что ввод действителен. Как вы должны справляться с предположениями? Вы утверждаете их в коде.Я думаю, что это делает код очень легко читаемым. Метод проверки содержит весь грязный код для устранения ошибок на стороне пользователя. Метод работы четко документирует свои предположения с утверждениями, а затем не должен работать с потенциально неверными данными.
Рассмотрим этот рефакторинг вашего примера:
источник