Чи є визначення змінної для назви аргументу методу гарною практикою?


73

Для читабельності я часто опиняюсь тим, що визначаю тимчасові змінні під час виклику функцій, таких як наступний код

var preventUndo = true;
doSomething(preventUndo);

Коротка версія цього до цього буде,

doSomething(true);

Але коли я повертаюся до коду, мені часто цікаво, на що trueйдеться. Чи існує умова для такого роду головоломки?


5
Ви використовуєте якусь IDE? Більшість матиме певний спосіб вказувати, які параметри є функції, яку ви викликаєте, що дещо зводить нанівець необхідність цього робити.
Меттью Шарлі

4
Я не використовую IDE, але навіть тоді я гадаю, що підказка потребує певних дій (наведення миші або перехід до рядка). Мені подобається знати, що робить мій код, просто дивлячись на нього.
методофакція

11
Якщо мова його підтримує, ви можете використати таке перерахування, якdoSomething( Undo.PREVENT )
James P.

4
Але можна визначити Undo = { PREVENT = true, DONT_PREVENT = false }. Але в JavaScript конвенція полягає в тому, щоб зробити це так: function myFunction( mandatoryArg1, mandatoryArg2, otherArgs ) { /*...*/ }і потім myFunction( 1, 2, { option1: true, option2: false } ).
xavierm02

6
Це безумовно залежить від мови. Якби це, наприклад, python, я б запропонував просто використовувати аргументи ключових слів, наприкладdoSomething(preventUndo=True)
Joel Cornett

Відповіді:


117

Пояснення змінних

Ваш випадок - приклад введення пояснення змінного рефакторингу. Коротше кажучи, пояснювальна змінна - це категорично не обов'язково, але дозволяє дати чітке ім’я чомусь з метою підвищення читабельності.

Код хорошої якості повідомляє про намір читача; і як професійний розробник читабельність та ремонтопридатність - ваші цілі №1.

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

editButton.Enabled = (_grid.SelectedRow != null && ((Person)_grid.SelectedRow).Status == PersonStatus.Active);

порівняно з дещо довшим, але, можливо, зрозумілішим:

bool personIsSelected = (_grid.SelectedRow != null);
bool selectedPersonIsEditable = (personIsSelected && ((Person)_grid.SelectedRow).Status == PersonStatus.Active)
editButton.Enabled = (personIsSelected && selectedPersonIsEditable);

Булеві параметри

Ваш приклад насправді підкреслює, чому булеві інтерфейси в API часто є поганою ідеєю - з боку виклику вони нічого не роблять, щоб пояснити, що відбувається. Поміркуйте:

ParseFolder(true, false);

Вам доведеться шукати, що означають ці параметри; якби вони були перерахунками, було б набагато зрозуміліше:

ParseFolder(ParseBehaviour.Recursive, CompatibilityOption.Strict);

Редагувати:

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


28
Якщо ви не використовуєте іменовані параметри (названі аргументи в .NET Framework), у цьому випадку doSomething(preventUndo: true);достатньо зрозуміло. Також створити перерахунок для кожного булевого інтерфейсу у вашому API? Серйозно?
Арсеній Муренко

12
@MainMa: Якщо мова, якою ви користуєтесь, недостатньо крута, щоб підтримувати названі аргументи, використання enum є хорошим варіантом. Це не означає, що слід систематично впроваджувати переписки скрізь.
Джорджіо

18
@MainMa - Щоб відповісти на це запитання, справа справді в тому, що у ваших API не повинно бути булеонів (принаймні, у ваших загальнодоступних). Вам потрібно буде змінити названий синтаксис аргументу, який, мабуть, не ідіоматичний (на момент написання), і в будь-якому випадку булевий параметр майже завжди означає, що ваш метод робить дві речі, і ви дозволяєте абоненту вибрати. Але суть моєї відповіді полягала в тому, що в використанні пояснювальних змінних у вашому коді немає нічого поганого; це насправді дуже хороша практика.
Даніель Б

3
Це постійна частина мови C #, для чого потрібно ще "основне прийняття"? Навіть для того, хто ще не знає про конструкцію (це означає, що ваші C # devs навіть не читали документи C #), очевидно, що це робить.
Nate CK

3
Ось чому MS випускає ці приємні підсумки всіх нових речей, які вони додавали в кожній версії, я не думаю, що це створює багато роботи для того, щоб прочитати один з цих кожні пару років: msdn.microsoft.com/en- us / library / bb383815% 28v = vs.100% 29.aspx
Nate CK

43

Не пишіть код, який вам не потрібен.

Якщо вам doSomething(true)важко зрозуміти, вам слід додати коментар:

// Do something and prevent the undo.
doSomething(true);

або, якщо мова його підтримує, додайте ім'я параметра:

doSomething(preventUndo: true);

В іншому випадку покладайтеся на свій IDE, щоб дати вам підпис названого методу:

введіть тут опис зображення

Випадки, коли це корисно

Введення додаткової змінної може бути корисним:

  1. Для налагодження:

    var productId = this.Data.GetLastProductId();
    this.Data.AddToCart(productId);
    

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

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

    // Even with indentation, this is unreadable.
    var doSomething(
        isSomethingElse ? 0 : this.getAValue(),
        this.getAnotherOne() ?? this.default,
        (a + b + c + d + e) * f,
        this.hello ? this.world : (this.hello2 ? this.world2 : -1));
    
  3. Якщо оцінка параметра занадто складна. Приклад коду, який я бачив:

    // Wouldn't it be easier to have several if/else's (maybe even in a separate method)?
    do(something ? (hello ? world : -1) : (programmers ? stackexchange : (com ? -1 : 0)));
    

Чому б не в інших випадках?

Чому не слід створювати додаткові змінні у простих випадках?

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

  2. Але через ризик відмежування імені ви надаєте змінній на ім'я параметра.

    Приклад:

    Скажімо, початковий код:

    void doSomething(bool preventUndo)
    {
        // Does something very interesting.
        undoHistory.removeLast();
    }
    
    // Later in code:
    var preventUndo = true;
    doSomething(preventUndo);
    

    Пізніше розробник працював над doSomethingповідомленнями про те, що нещодавно історія скасування запровадила два нові методи:

    undoHistory.clearAll() { ... }
    undoHistory.disable() { ... }
    

    Зараз, preventUndoздається, не дуже зрозуміло. Чи означає це, що буде попереджено лише останню дію? А може це означає, що користувач більше не зможе використовувати функцію скасування? Або що історія скасування буде очищена? Чіткіші назви були б:

    doSomething(bool hideLastUndo) { ... }
    doSomething(bool removeAllUndo) { ... }
    doSomething(bool disableUndoFeature) { ... }
    

    Отже, тепер у вас є:

    void doSomething(bool hideLastUndo)
    {
        // Does something very interesting.
        undoHistory.removeLast();
    }
    
    // Later in code, very error prone, while the signature of the method is clear:
    var preventUndo = true;
    doSomething(preventUndo);
    

А як із переліками?

Деякі інші люди запропонували використовувати переписки. Хоча вона вирішує найближчу проблему, вона створює більшу. Давайте подивимось:

enum undoPrevention
{
    keepInHistory,
    prevent,
}

void doSomething(undoPrevention preventUndo)
{
    doTheJob();
    if (preventUndo == undoPrevention.prevent)
    {
        this.undoHistory.discardLastEntry();
    }
}

doSomething(undoPrevention.prevent);

Проблеми з цим:

  1. Це занадто багато коду. if (preventUndo == undoPrevention.prevent)? Серйозно ?! Я не хочу писати подібні слова ifкожен раз.

  2. Додавання елемента до enum пізніше дуже спокусливо, якщо я використовую той самий enum деінде. Що робити, якщо я його модифікую так:

    enum undoPrevention
    {
        keepInHistory,
        prevent,
        keepButDisable, // Keeps the entry in the history, but makes it disabled.
    }
    

    Що буде зараз? Чи буде doSomethingметод працювати, як очікувалося? Щоб запобігти цьому, потрібно буде написати цей метод таким чином з самого початку:

    void doSomething(undoPrevention preventUndo)
    {
        if (![undoPrevention.keepInHistory, undoPrevention.prevent].contains(preventUndo))
        {
            throw new ArgumentException('preventUndo');
        }
    
        doTheJob();
        if (preventUndo == undoPrevention.prevent)
        {
            this.undoHistory.discardLastEntry();
        }
    }
    

    Варіант, в якому використовуються булеви, починає виглядати так приємно!

    void doSomething(bool preventUndo)
    {
        doTheJob();
        if (preventUndo)
        {
            this.undoHistory.discardLastEntry();
        }
    }
    

3
"Це занадто багато коду. Якщо (prevenUndo == undoPrevention.prevent)? Серйозно ?! Я не хочу писати такі ifs кожен раз.": А як використовувати старий хороший оператор перемикача? Крім того, якщо ви використовуєте булевий, вам все одно потрібний оператор if. Чесно кажучи, ваша критика з цього приводу мені здається трохи штучною.
Джорджіо

1
Тут я пропускаю альтернативне рішення. Ви хочете сказати, що він повинен дотримуватися сказаного - нічого простого істинного та неправдивого і покладатися на IDE (яким він не користується)? Коментар може зігнути, як назва змінної.
Безпечний

2
@superM: Мені не важко змінити назву тимчасової змінної, яка використовується лише для виклику. Якщо ім'я перерахунку буде змінено, то це ще краще, оскільки код виклику більше не працюватиме і кидає помилку прямо вам в обличчя. Якщо функціональність функції кардинально змінюється розширенням enum, то вам доведеться переглянути всі виклики для подальшої коректності, у будь-якому випадку, інакше ви програмуєте на надію, а не на логіку. Навіть не думати про зміну значення, наприклад , заперечуючи , preventUndoщоб allowUndoв підписі ...
Secure

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

7
"... покладайтеся на свій IDE, щоб дати вам підпис названого методу" - це корисно для того, коли ви пишете код, але не так сильно, коли ви читаєте його. Коли я читаю код для класу, я хочу знати, що він робить, просто дивлячись на нього. Якщо вам потрібно покластися на IDE для читабельності, ваш код не є самодокументуванням.
Філ

20

Також не слід писати методи з булевими прапорами.

Цитуючи Роберта К. Мартіна, у своїй книзі «Чистий кодекс» (ISBN-13 978-0-13-235088-4) йдеться про те, що «Передача булевої функції у функцію - це справді жахлива практика».

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

DoSomething()
{...

DoSomethingUndoable()
{....

7
За цією логікою моєму єдиному конструктору HotDog потрібно було б приблизно 16 різних методів: HotDogWithMustardRelishKrautOnion (), HotDogWithMustardNorelishKrautOnion () тощо. Або це може бути простий HotDogWithOptions (int options), в якому я трактую параметри як бітове поле, але потім ми повертаємось до одного методу, який робить кілька нібито різних речей. Тож якщо я переходжу до першого варіанту, чи потрібно писати великі умови, щоб розібрати, який конструктор викликати, виходячи з речей, які б інакше були булевими параметрами? І якщо Q використовує int, цей A не відповідає Q.
Caleb

4
Прочитавши всі відповіді і переглянувши свій код, я приходжу до висновку, що це правильний спосіб зробити це. doSomethingUndoable()може зафіксувати зміни, а потім зателефонуватиdoSomething()
методофакція

1
Отже, якщо у мене є функція, яка багато обробляє і має можливість надсилати електронний лист після його завершення, у мене не повинно бути булевого аргументу, який може перешкоджати надсиланню електронної пошти, я повинен створити окрему функцію?
якуц

2
@Caleb У цьому випадку я б або зробив хот-дог і додав інгредієнти по черзі, або сильно набраною мовою я передавав би об'єкт HotDogSettings, в якому я б встановив усі булеві прапори. У мене не було б 15 різних справжніх / хибних прапорів, які були б кошмаром для підтримки. пам’ятайте, що код не стосується технічного обслуговування, оскільки це 80% вартості програми. var hd = MakeHotDog (); hd.Add (цибуля); ...
Nick B.

2
@Caleb Я думаю, що відмінність полягає в тому, що ваш приклад використовує булеві дані як фактичне поле даних, тоді як більшість застосувань - це керувати потоком виконання; отже, і дядько Боба проти неї поругав. Також його порада трохи в крайній бік - наступні кілька рядків у книзі не рекомендують мати більше 2 параметрів, що, можливо, ще більш екстремально позиціонує. Існує метод до божевілля. Ви абсолютно праві, що він не відповідає на запитання, помилка, яку я зробив у власній відповіді.
Даніель Б

5

Якщо ви подивитесь на два класи, щоб побачити, наскільки вони поєднані, одна з категорій - це з'єднання даних , яке посилається на код у одному класі методів виклику іншого класу та просто передавання даних, наприклад, за який місяць ви хочете отримати звіт та інший категорія - це керування сполученням , викликом методів і передачею чогось, що контролює поведінку методу. Приклад, який я використовую в класі - це verboseпрапор або reportTypeпрапор, але preventUndoтакож є чудовим прикладом. Як ви недавно продемонстрували, керування з'єднанням важко читати код виклику та розуміти, що відбувається. Це також робить код виклику вразливим до змін, doSomething()які використовують один і той же прапор для управління і скасуванням, і архівуванням, або додаванням іншого параметра доdoSomething() керувати архівуванням, таким чином порушуючи свій код тощо.

Проблема полягає в тому, що код занадто щільно пов'язаний. Передача булінгу для контролю поведінки, на мій погляд, є ознакою поганого API. Якщо ви володієте API, змініть його. Два методи, doSomething()і doSomethingWithUndo(), було б краще. якщо ви не володієте ним, напишіть два способи обгортки самостійно в код, яким ви володієте, і один з них дзвонить, doSomething(true)а другий дзвонить doSomething(false).


4

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

Змінна повинна бути названа за їх роллю в нинішньому обсязі. Не область, куди вони надсилаються.


1
роль змінної в поточній області полягає в тому, щоб сказати, для чого вона використовується. Я не бачу, як це суперечить використанню тимчасовими змінними ОП.
superM

4

Що я б робив у JavaScript - це функція приймати об’єкт як єдиний параметр, подібний до цього:

function doSomething(settings) {
    var preventUndo = settings.hasOwnProperty('preventUndo') ? settings.preventUndo : false;
    // Deal with preventUndo in the normal way.
}

Потім зателефонуйте за допомогою:

doSomething({preventUndo: true});

ХА !!! Ми обоє зробили doSomething(x)метод! хаха ... Досі я навіть не помічав твого допису.
м'ясо

Що трапилося б, якби я передав рядок "noUndo", і як людині, яка використовує ваш підпис, зрозуміло, які параметри повинні містити, не дивлячись на реалізацію?
Нік Б.

1
Документуйте свій код. Це роблять усі інші. Це полегшує читання коду, писати його потрібно лише один раз.
їзда2

1
@NickB. конвенція потужна. Якщо більшість вашого коду приймає об'єкти з аргументами, це зрозуміло.
Оріп

4

Мені подобається використовувати мовні функції, щоб я зрозуміти себе. Наприклад, у C # ви можете вказати параметри за назвою:

 CallSomething(name: "So and so", age: 12, description: "A random person.");

У JavaScript я зазвичай вважаю за краще використовувати об'єкт параметрів як аргумент з цієї причини:

function doSomething(args) { /*...*/ }

doSomething({ name: 'So and so', age: 12, description: 'A random person.' });

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


1
Ось і "недолік" для мовних текстів. Ви не можете реально застосувати підпис без певної перевірки. Я не знав, що ви можете додати такі імена в JS.
Джеймс П.

1
@JamesPoulson: Ви, мабуть, знали, що можете це зробити в JS і просто не усвідомлювали цього. Все закінчилося в JQuery: $.ajax({url:'', data:''})і т. Д.
поблукайте

Правда. На перший погляд це здається незвичним, але він схожий на вбудовані псевдооб'єкти, які можуть існувати в деяких мовах.
Джеймс П.

3

Я вважаю, що це найпростіше і найпростіше для читання:

enum Undo { ALLOW, PREVENT }

doSomething(Undo u) {
    if (Undo.ALLOW == u) {
        // save stuff to undo later.
    }
    // do your thing
}

doSomething(Undo.ALLOW);

MainMaе це не любить. Можливо, нам доведеться погодитися не погодитися, або ми можемо використовувати рішення, яке пропонує Джошуа Блох:

enum Undo {
    ALLOW {
        @Override
        public void createUndoBuffer() {
            // put undo code here
        }
    },
    PREVENT {
        @Override
        public void createUndoBuffer() {
            // do nothing
        }
    };

    public abstract void createUndoBuffer();
}

doSomething(Undo u) {
    u.createUndoBuffer();
    // do your thing
}

Тепер, якщо ви коли-небудь додасте Undo.LIMITED_UNDO, ваш код не буде компілюватися, якщо ви не реалізуєте метод createUndoBuffer (). І в doSomething () немає if (Undo.ALLOW == u). Я робив це обома способами, і другий метод досить важкий і трохи важко зрозуміти, коли перерахунок "Скасувати" розшириться на сторінки та сторінки коду, але це змушує задуматися. Зазвичай я дотримуюся більш простого методу заміни простого булевого перерахунку на 2 значення, поки у мене немає підстав для зміни. Коли я додаю третє значення, я використовую свій IDE для "Find-usages" і тоді все виправляю.


2

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

Я можу придумати дві альтернативи, які не передбачають додаткової змінної:

1. Використовуйте додатковий коментар

doSomething(/* preventUndo */ true);

2. Використовуйте двозначне перерахунок замість булевого

enum Options
{
    PreventUndo,
    ...
}

...

doSomething(PreventUndo);

Ви можете використовувати альтернативу 2, якщо ваша мова підтримує переписки.

EDIT

Звичайно, використання названих аргументів також є варіантом, якщо ваша мова їх підтримує.

Щодо додаткового кодування, необхідного перепискам, воно мені справді здається незначним. Замість

if (preventUndo)
{
    ...
}

ти маєш

if (undoOption == PreventUndo)
{
    ...
}

або

switch (undoOption)
{
  case PreventUndo:
  ...
}

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


2

Я згоден з тим, що сказав @GlenPeterson:

doSomething(Undo.ALLOW); // call using a self evident enum

але також цікавим буде наступне, оскільки, як мені здається, є лише два можливості (правдиві чи помилкові)

//Two methods    

doSomething()  // this method does something but doesn't prevent undo

doSomethingPreventUndo() // this method does something and prevents undo

2
Гарна ідея - я не думав про це. Коли ви ускладнюєтесь, як doSomething (String, String, String, булева, булева, булева), то названі константи - єдине розумне рішення. Ну, Джош Блок пропонує об'єкт заводу та конструктора, як у: MyThingMaker thingMaker = MyThingMaker.new (); thingMaker.setFirstString ("Привіт"); thingMaker.setSecondString ("Там"); тощо ... Річ t = thingMaker.makeIt (); t.doSomething (); Це просто набагато більше роботи, тому краще було того вартий.
GlenPeterson

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

@GlenPeterson Фабрика - це можливість і можлива в Javascript (згадується ОП).
Джеймс П.

2

Оскільки ви питаєте в основному про JavaScript, використовуючи coffeescript, ви можете мати такий аргумент, як синтаксис, дуже просто:

# declare method, ={} declares a default value to prevent null reference errors
doSomething = ({preventUndo} = {}) ->
  if preventUndo
    undo = no
  else
    undo = yes

#call method
doSomething preventUndo: yes
#or 
doSomething(preventUndo: yes)

компілює до

var doSomething;

doSomething = function(_arg) {
  var preventUndo, undo;
  preventUndo = (_arg != null ? _arg : {}).preventUndo;
  if (preventUndo) {
    return undo = false;
  } else {
    return undo = true;
  }
};

doSomething({
  preventUndo: true
});

doSomething({
  preventUndo: true
});

Повеселіться на http://js2coffee.org/, щоб спробувати можливості


Я використовую CoffeeScript лише тоді, коли мені потрібно уникати божевільності OOP від ​​JavaScript. Це приємне рішення, яке я можу використати, коли кодує поодинці, було б важко виправдати колегам, що я передаю об'єкт замість булевого заради читабельності!
методофакція

1

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

var doSomethingOptions = new Array();

doSomethingOptions["PREVENTUNDO"] = true;
doSomethingOptions["TESTMODE"] = false;

doSomething( doSomethingOptions );

// ...

function doSomething( doSomethingOptions ){
    // Check for null here
    if( doSomethingOptions["PREVENTUNDO"] ) // ...
}

Я усвідомлюю, що це рефлекс когось із сильно типізованого тла і може бути не таким практичним, але вважаю це оригінальністю.

Інша можливість - мати об’єкт, і це також можливо в Javascript. Я не на 100% впевнений, що це синтаксично правильно. Подивіться на такі моделі, як Фабрика, для подальшого натхнення.

function SomethingDoer( preventUndo ) {
    this.preventUndo = preventUndo;
    this.doSomething = function() {
            if( this.preventUndo ){
                    // ...
            }
    };
}

mySomethingDoer = new SomethingDoer(true).doSomething();

1
Я думаю, що це можна краще записати в dot-notation ( doSomethingOptions.PREVENTUNDO) замість позначення доступу до масиву.
Paŭlo Ebermann

1

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

Я думаю, що корисно зауважити, що ця проблема в основному відвертається, коли мова програмування підтримує названі аргументи / аргументи ключових слів, як-от у C # 4 та Python, або де аргументи методу переплітаються в назві методу, як у Smalltalk або Objective-C.

Приклади:

// C# 4
foo.doSomething(preventUndo: true);
# Python
foo.doSomething(preventUndo=True)
// Objective-C
[foo doSomethingWith:bar shouldPreventUndo:YES];

0

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

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


Отже, ви перетворили б функцію з булевим аргументом у дві функції, які відрізняються лише крихітною частиною їх коду (де оригінал мав би if(param) {...} else {...})?
Paŭlo Ebermann

-1
int preventUndo = true;
doSomething(preventUndo);

Хороший компілятор для мов низького рівня, таких як C ++, оптимізує машинний код вище 2 рядка, як показано нижче:

doSomething(true); 

тому це не має значення в продуктивності, але підвищить читабельність.

Також корисно використовувати змінну у випадку, якщо вона стане змінною пізніше і може приймати й інші значення.

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