Чи краще захистити виклик методу або сам метод?


12

Я пишу заявку, і я дійшов до цього пункту:

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, вони виконуються лише у тому випадку, якщо у налаштуваннях є правильний прапор.

Це щось таке, що я насправді повинен вважати проблемою?

У моєму нинішньому контексті дуже малоймовірно, що ці два методи будуть викликані поза цим методом, але ніхто не може цього гарантувати.


5
Це залежить від того, чи може вам колись потрібно зателефонувати на GiveApples чи GiveBananas, не перевіряючи попередньо. Оскільки захист пов'язаний із методом, він, ймовірно, належить до методу.
Роберт Харві

Відповіді:


13

Я думаю, що охоронці як щось, чому повинен дотримуватися метод . У вашому прикладі метод не повинен давати яблука, якщо Settings.GiveApples є помилковим.

Якщо це так, то захисник безумовно належить всередині методу. Це запобігає випадковому виклику його з іншого пункту вашої програми, не попередньо перевіряючи охоронців.

З іншого боку, якщо налаштування стосуються лише методу виклику, а інший спосіб десь у вашому коді може давати GiveApples незалежно від налаштування, то це не захист і, мабуть, має бути в коді виклику.


5

Поставте оберіг у межах самого методу. Споживач GiveApples()або GiveBananas()не повинен нести відповідальність за керування охоронцями GiveApples().

З точки зору дизайну, SomeMethod()слід знати лише, що йому потрібні фрукти, і не слід дбати про те, що потрібно робити для того, щоб отримати її. Абстракція пошуку фруктів стає витікаючою, якщо SomeMethod()вона відповідає за те, що існує глобальна установка, яка дозволяє отримати певні фрукти. Це каскади, якщо ваш механізм захисту коли-небудь змінюється, як тепер усі методи, які потрібно GetApples()або GetBananas()потрібно переробити окремо для впровадження цієї нової охорони. Також дуже легко забути спробувати отримати плоди без цієї перевірки, коли ви пишете код.

Що слід враховувати в цьому сценарії - це те, як ваша програма повинна реагувати, коли налаштування не дозволяють вашій програмі давати плоди.


4

Як правило, часто корисно розділити обов'язки тестування чогось типу зовнішніх налаштувань, а також "основний код бізнесу" GiveApples. З іншого боку, мати функції, які об'єднують те, що належить разом, також є хорошою ідеєю. Ви можете домогтися обох цілей, переформулюючи свій код таким чином:

private void SomeMethod()
{
    GiveApplesIfActivated();
    GiveBananasIfActivated();
}

private void GiveApplesIfActivated()
{
    if (Settings.GiveApples)
    {
        GiveApples();
    }
}

private void GiveBananasIfActivated()
{
    if (Settings.GiveBananas)
    {
        GiveBananas();
    }
}

private void GiveApples()
{
    ...
}

private void GiveBananas()
{
    ...
}

Це дає кращі шанси переробити код GiveApplesта / або GiveBananasв окреме місце без будь-яких залежностей від Settingsкласу. Це, очевидно, вигідно, коли ви хочете викликати ті методи в одиничному тесті, який не стосується жодного Settings.

Однак, якщо у вашій програмі завжди неправильно, за будь-яких обставин, навіть у тестовому контексті, викликати щось на зразок GiveApplesпоза контекстом, де Settings.GiveApplesперевіряється спочатку, і ви відчуваєте, що лише функція, як GiveApplesбез Settingsперевірки, не схильна до помилок , тоді дотримуйтесь варіанту, де ви протестуєте Settings.GiveApplesвсередині GiveApples.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.