Я пишу заявку, и я дошел до этого:
private void SomeMethod()
{
if (Settings.GiveApples)
{
GiveApples();
}
if (Settings.GiveBananas)
{
GiveBananas();
}
}
private void GiveApples()
{
...
}
private void GiveBananas()
{
...
}
Это выглядит довольно просто. Есть некоторые условия, и если они верны, методы вызываются. Тем не менее, я подумал, что лучше сделать так:
private void SomeMethod()
{
GiveApples();
GiveBananas();
}
private void GiveApples()
{
if (!Settings.GiveApples)
{
return;
}
...
}
private void GiveBananas()
{
if (!Settings.GiveBananas)
{
return;
}
...
}
Во втором случае каждый из методов защищает сам себя, поэтому даже если какой-либо из этих методов GiveApples
или GiveBananas
вызывается извне SomeMethod
, они будут выполняться только в том случае, если в настройках указан правильный флаг.
Это то, что я должен рассматривать как проблему?
В моем текущем контексте очень маловероятно, что эти два метода будут вызваны извне этого метода, но никто не может гарантировать это.
design
conditions
Никола
источник
источник
Ответы:
Я думаю о охранниках как о чем-то, что метод должен подчиняться. В вашем примере метод не должен давать яблоки, если Settings.GiveApples имеет значение false.
Если это так, то охранник определенно принадлежит внутри метода. Это предотвращает случайный вызов из другого пункта приложения без предварительной проверки охранников.
С другой стороны, если настройки применяются только к вызывающему методу, а другой метод где-то еще в вашем коде может выдавать GiveApples независимо от настройки, тогда это не защита и, вероятно, должно быть в вызывающем коде.
источник
Разместите охрану в самом методе. Потребитель
GiveApples()
илиGiveBananas()
не должен нести ответственность за управление охранойGiveApples()
.С точки зрения дизайна
SomeMethod()
следует только знать, что ему нужны плоды, и не должно заботиться о том, что нужно приложению, чтобы его получить. Абстракция поиска фруктов становится утечкой, еслиSomeMethod()
она отвечает за знание того, что существует глобальная настройка, которая разрешает получение определенных фруктов. Это каскадно, если ваш защитный механизм когда-либо изменяется, как теперь все методы, которые должныGetApples()
илиGetBananas()
должны быть подвергнуты рефакторингу отдельно для реализации этой новой защиты. Также очень легко забыть попробовать и получить фрукты без этой проверки, когда вы пишете код.В этом сценарии вы должны учитывать, как ваше приложение должно реагировать, когда настройки не позволяют вашему приложению приносить плоды.
источник
Как правило, хорошей идеей является разделение ответственности за тестирование чего-то вроде внешних настроек и «основного бизнес-кода»
GiveApples
. С другой стороны, наличие функций, которые группируют вместе то, что принадлежит друг другу, также является хорошей идеей. Вы можете достичь обеих целей путем рефакторинга вашего кода следующим образом:Это дает вам больше шансов реорганизовать код
GiveApples
и / илиGiveBananas
в отдельное место без каких-либо зависимостей отSettings
класса. Это, очевидно, полезно, когда вы хотите вызывать те методы в модульном тесте, который не заботится ни о какомSettings
.Однако, если в вашей программе всегда неправильно, при любых обстоятельствах, даже в контексте тестирования, вызывать что-то вроде
GiveApples
вне контекста, гдеSettings.GiveApples
сначала проверяется, и у вас сложилось впечатление, что просто предоставление функции, подобнойGiveApples
безSettings
проверки, подвержено ошибкам , затем придерживайтесь варианта, в котором вы тестируетеSettings.GiveApples
внутриGiveApples
.источник