Definire una variabile per nominare un argomento di metodo è una buona pratica?


73

Per motivi di leggibilità, mi trovo spesso a definire variabili temporanee durante la chiamata di funzioni, come il seguente codice

var preventUndo = true;
doSomething(preventUndo);

La versione più breve di questo sarebbe:

doSomething(true);

Ma quando torno al codice mi chiedo spesso a cosa si trueriferisca. Esiste una convenzione per questo tipo di enigma?


5
Usi qualche tipo di IDE? La maggior parte avrà una sorta di modo per indicare quali sono i parametri per la funzione che stai chiamando che annulla in qualche modo la necessità di farlo.
Matthew Scharley,

4
Non uso un IDE, ma anche allora suppongo che il suggerimento richiederebbe una sorta di azione (passaggio del mouse o spostamento sulla linea). Mi piace sapere cosa sta facendo il mio codice semplicemente guardandolo.
methodofaction

11
Se la lingua lo supporta, è possibile utilizzare un elenco comedoSomething( Undo.PREVENT )
James P.

4
Ma puoi definire Undo = { PREVENT = true, DONT_PREVENT = false }. Ma in JavaScript, la convenzione è di farlo in questo modo: function myFunction( mandatoryArg1, mandatoryArg2, otherArgs ) { /*...*/ }e poi myFunction( 1, 2, { option1: true, option2: false } ).
xavierm02,

6
Dipende sicuramente dalla lingua. Se questo fosse python, per esempio, suggerirei di usare solo argomenti per parole chiave, ad esdoSomething(preventUndo=True)
Joel Cornett,

Risposte:


117

Spiegare le variabili

Il tuo caso è un esempio dell'introduzione che spiega il refactoring variabile . In breve, una variabile esplicativa non è strettamente necessaria, ma consente di dare un nome chiaro a qualcosa, con l'obiettivo di aumentare la leggibilità.

Un codice di buona qualità comunica l' intenzione al lettore; e come sviluppatore professionista la leggibilità e la manutenibilità sono i tuoi obiettivi n. 1.

Pertanto, la regola empirica che consiglierei è questa: se lo scopo del tuo parametro non è immediatamente ovvio, sentiti libero di usare una variabile per dargli un buon nome. Penso che questa sia una buona pratica in generale (se non abusata). Ecco un esempio rapido e inventato: considera:

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

rispetto al leggermente più lungo, ma probabilmente più chiaro:

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

Parametri booleani

Il tuo esempio in realtà evidenzia perché i booleani nelle API sono spesso una cattiva idea : sul lato chiamante, non fanno nulla per spiegare cosa sta succedendo. Tener conto di:

ParseFolder(true, false);

Dovresti cercare cosa significano quei parametri; se fossero enumerazioni, sarebbe molto più chiaro:

ParseFolder(ParseBehaviour.Recursive, CompatibilityOption.Strict);

Modificare:

Aggiunti titoli e scambiato l'ordine dei due paragrafi principali, perché troppe persone si stavano concentrando sulla parte dei parametri booleani (per essere onesti, in origine era il primo paragrafo). Ha anche aggiunto un esempio alla prima parte.


28
A meno che non si utilizzino parametri denominati (argomenti denominati in .NET Framework), nel qual caso doSomething(preventUndo: true);è abbastanza chiaro. Inoltre, creando un enum per ogni valore booleano nella tua API? Sul serio?
Arseni Mourzenko,

12
@MainMa: se la lingua che stai usando non è abbastanza fredda per supportare argomenti con nome, usare una enum è una buona opzione. Questo non significa che dovresti introdurre sistematicamente enumerazioni ovunque.
Giorgio,

18
@MainMa - Per rispondere a questa domanda, il punto è che non dovresti avere booleani nelle tue API (almeno, quelle pubbliche). Dovresti passare a una sintassi dell'argomento denominato, che probabilmente non è idiomatica (al momento della scrittura), e in ogni caso, un parametro booleano indica quasi sempre che il tuo metodo fa due cose e stai permettendo al chiamante di scegliere. Ma il punto della mia risposta è che non c'è niente di sbagliato nell'usare la spiegazione delle variabili nel codice; in realtà è un'ottima pratica.
Daniel B,

3
È una parte permanente del linguaggio C #, di quale altra "accettazione mainstream" ha bisogno? Anche per qualcuno che non è già a conoscenza del costrutto (il che significa che i tuoi sviluppatori C # non hanno nemmeno letto i documenti C #), è abbastanza ovvio che cosa fa.
Nate CK,

3
Ecco perché MS rilascia quei bei riassunti di tutte le nuove cose che hanno aggiunto in ogni versione, non credo che crei molto lavoro per leggere uno di questi ogni due anni: msdn.microsoft.com/en- us / library / bb383815% 28v = vs.100% 29.aspx
Nate CK

43

Non scrivere codice che non ti serve.

Se trovi doSomething(true)difficile da capire, dovresti aggiungere un commento:

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

oppure, se la lingua lo supporta, aggiungi il nome del parametro:

doSomething(preventUndo: true);

Altrimenti, affidati al tuo IDE per darti la firma del metodo chiamato:

inserisci qui la descrizione dell'immagine

Casi in cui è utile

Inserire una variabile aggiuntiva può essere utile:

  1. A scopo di debug:

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

    Lo stesso codice può essere scritto in una sola riga, ma se si desidera inserire un punto di interruzione prima di aggiungere un prodotto al carrello per vedere se l'id del prodotto è corretto, scrivere due righe anziché una è una buona idea.

  2. Se hai un metodo con molti parametri e ogni parametro passa da una valutazione. In una riga, questo può diventare totalmente illeggibile.

    // 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. Se la valutazione di un parametro è troppo complicata. Un esempio di un codice che ho visto:

    // 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)));
    

Perché non in altri casi?

Perché non dovresti creare variabili aggiuntive in casi semplici?

  1. Non a causa dell'impatto sulle prestazioni. Questo sarebbe un presupposto molto sbagliato di uno sviluppatore principiante che sta ottimizzando micro la sua app. Non vi è alcun impatto sulle prestazioni nella maggior parte delle lingue, poiché il compilatore incorporerà la variabile. In quelle lingue in cui il compilatore non lo fa, potresti guadagnare qualche microsecondo incorporandolo manualmente, il che non ne vale la pena. Non farlo.

  2. Ma a causa del rischio di dissociare il nome assegnato alla variabile con il nome del parametro.

    Esempio:

    Diciamo che il codice originale è:

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

    Più tardi, uno sviluppatore che sta lavorando su doSomethingavvisi che recentemente, la cronologia degli annullamenti ha introdotto due nuovi metodi:

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

    Ora, preventUndonon sembra molto chiaro. Significa che sarà impedita solo l'ultima azione? O forse significa che l'utente non sarà più in grado di utilizzare la funzione di annullamento? O che la cronologia degli annullamenti verrà cancellata? I nomi più chiari sarebbero:

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

    Quindi ora hai:

    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);
    

E gli enum?

Alcune altre persone hanno suggerito di usare enums. Mentre risolve il problema immediato, ne crea uno più grande. Diamo un'occhiata:

enum undoPrevention
{
    keepInHistory,
    prevent,
}

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

doSomething(undoPrevention.prevent);

Problemi con questo:

  1. È troppo codice. if (preventUndo == undoPrevention.prevent)? Sul serio?! Non voglio scrivere queste cose ifogni volta.

  2. Aggiungere un elemento all'enum è molto allettante in seguito, se sto usando lo stesso enum da qualche altra parte. Cosa succede se lo modifico in questo modo:

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

    Cosa succederà adesso? Il doSomethingmetodo funzionerà come previsto? Per evitare ciò, sarebbe necessario scrivere questo metodo in questo modo dall'inizio:

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

    La variante che usa i booleani inizia a sembrare così bella!

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

3
"È troppo codice. If (preventUndo == undoPrevention.prevent)? Davvero ?! Non voglio scrivere tali if ogni volta.": Che ne dici di usare una buona vecchia istruzione switch? Inoltre, se usi un valore booleano, devi comunque avere un'istruzione if. Onestamente, le tue critiche su questo punto mi sembrano un po 'artificiali.
Giorgio,

1
Mi manca una soluzione alternativa qui. Stai dicendo che dovrebbe attenersi al dire niente di vero e falso e fare affidamento sull'IDE (che non usa)? Un commento potrebbe marcire come il nome della variabile.
Sicuro il

2
@superM: Non trovo molto più difficile cambiare il nome di una variabile temporanea utilizzata solo per la chiamata. Se il nome di un enum viene modificato, allora è ancora meglio, perché il codice di chiamata non verrà più eseguito e genererà un errore sul tuo viso. Se la funzionalità della funzione viene radicalmente modificata da un'estensione enum, allora è necessario rivisitare tutte le chiamate per ulteriore correttezza, comunque, altrimenti si programma sulla speranza, non sulla logica. Nemmeno di pensare a cambiare i valori, ad esempio negando preventUndoa allowUndonella firma ...
Fissare

4
@superM mantenere i commenti sincronizzati con il codice è davvero molto soggetto a problemi, poiché non hai aiuto dal tuo compilatore nella tua ricerca di incoerenze.
Buhb,

7
"... fai affidamento sul tuo IDE per darti la firma del metodo chiamato" - questo è utile per quando scrivi il codice, ma non tanto quando lo leggi. Quando leggo il codice per una classe, voglio sapere cosa sta facendo semplicemente guardandolo. Se devi fare affidamento sull'IDE per la leggibilità, il tuo codice non è auto-documentante.
Phil

20

Né, non dovresti scrivere metodi con flag booleani.

Per citare Robert C. Martin nel suo libro Clean Code (ISBN-13 978-0-13-235088-4), "Passare un booleano in una funzione è una pratica davvero terribile".

Per parafrasarlo, il ragionamento è che il fatto che tu abbia un interruttore vero / falso significa che molto probabilmente il tuo metodo sta facendo due cose diverse (cioè "Fai qualcosa con annulla" e "Fai qualcosa senza annulla"), e quindi dovrebbe essere diviso in due metodi diversi (che possono internamente chiamare la stessa cosa).

DoSomething()
{...

DoSomethingUndoable()
{....

7
Secondo questa logica, il mio unico costruttore di HotDog dovrebbe avere circa 16 metodi diversi: HotDogWithMustardRelishKrautOnion (), HotDogWithMustardNorelishKrautOnion () e così via. Oppure, potrebbe essere un semplice HotDogWithOptions (opzioni int), in cui interpreto le opzioni come un campo bit, ma poi torniamo a un metodo che fa diverse cose presumibilmente diverse. Quindi, se vado con la prima opzione, devo scrivere un grande condizionale per risolvere quale costruttore chiamare in base a cose che altrimenti sarebbero stati parametri booleani? E se il Q usa un int, questo A non risponde al Q.
Caleb

4
Dopo aver letto tutte le risposte e visto il mio codice, arrivo alla conclusione che questo è il modo giusto di farlo. doSomethingUndoable()potrebbe acquisire le modifiche e quindi chiamaredoSomething()
methodofaction il

1
Quindi, se ho una funzione che esegue molte elaborazioni e ha un'opzione per inviare un'e-mail al termine, non dovrei avere un argomento booleano che possa impedire l'invio dell'e-mail, dovrei creare una funzione separata?
yakatz,

2
@Caleb In questo caso o farei un hot dog e aggiungerei gli ingredienti uno per uno, o in una lingua fortemente tipizzata passerei un oggetto HotDogSettings in cui avrei impostato tutte le bandiere booleane. Non avrei 15 diverse bandiere vero / falso che sarebbe un incubo da mantenere. ricorda che il codice riguarda la manutenzione e non la scrittura, in quanto è l'80% del costo dell'applicazione. var hd = MakeHotDog (); hd.Add (Onion); ...
Nick B.

2
@Caleb Penso che la distinzione sia che il tuo esempio usa i booleani come un vero campo dati, mentre la maggior parte degli usi di esso è per guidare il flusso di esecuzione; quindi la ringhiera dello zio Bob contro di essa. Inoltre, il suo consiglio è un po 'estremo: le prossime righe del libro sconsigliano di avere più di 2 parametri, il che è probabilmente una posizione ancora più estrema. C'è un metodo per la follia però. Hai assolutamente ragione che non risponde alla domanda, un errore che ho fatto nella mia risposta.
Daniel B,

5

Quando guardi due classi per vedere quanto sono accoppiate, una delle categorie è l'accoppiamento dei dati , che si riferisce al codice in una classe che chiama i metodi di un'altra classe e passa semplicemente i dati, come per quale mese vuoi un rapporto, e un'altra categoria è l' accoppiamento di controllo , i metodi di chiamata e il passaggio in qualcosa che controlla il comportamento del metodo. L'esempio che uso in classe è una verbosebandiera o una reportTypebandiera, ma preventUndoè anche un ottimo esempio. Come hai appena dimostrato, l'accoppiamento di controllo rende difficile leggere il codice chiamante e capire cosa sta succedendo. Inoltre, rende il codice chiamante vulnerabile alle modifiche doSomething()che utilizzano lo stesso flag per controllare sia l'annullamento che l'archiviazione o l'aggiunta di un altro parametro adoSomething() per controllare l'archiviazione, rompendo così il codice e così via.

Il problema è che il codice è troppo stretto. Passare un bool per controllare il comportamento è, a mio avviso, un segno di una cattiva API. Se possiedi l'API, modificala. Due metodi doSomething()e doSomethingWithUndo(), sarebbe meglio. se non lo possiedi, scrivi tu stesso due metodi wrapper nel codice che possiedi e fai chiamare uno di loro doSomething(true)e l'altro doSomething(false).


4

Non è il ruolo del chiamante definire il ruolo degli argomenti. Vado sempre per la versione in linea e controllo la firma della funzione chiamata se ho dei dubbi.

La variabile deve avere il nome del loro ruolo nell'ambito corrente. Non l'ambito in cui vengono inviati.


1
il ruolo della variabile nell'ambito attuale è quello di dire a cosa serve. Non vedo come questo contraddica l'uso delle variabili temporanee da parte di OP.
superM

4

Quello che vorrei fare in JavaScript è avere la funzione prendere un oggetto come unico parametro qualcosa del genere:

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

Quindi chiamalo con:

doSomething({preventUndo: true});

HA !!! Entrambi abbiamo fatto un doSomething(x)metodo! lol ... non ho nemmeno notato il tuo post fino ad ora.
carne

Cosa succederebbe se passassi una stringa "noUndo", e come è chiaro per la persona che usa la tua firma quali impostazioni dovrebbe contenere senza esaminare l'implementazione?
Nick B.

1
Documenta il tuo codice. Questo è quello che fanno tutti gli altri. Rende più facile la lettura del codice, la scrittura deve avvenire una sola volta.
ridecar2,

1
@NickB. la convenzione è potente. Se la maggior parte del codice accetta oggetti con argomenti, questo è chiaro.
orip,

4

Sono appassionato di sfruttare le funzionalità del linguaggio per aiutare me stesso a chiarire. Ad esempio in C # è possibile specificare i parametri per nome:

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

In JavaScript, di solito preferisco usare un oggetto options come argomento per questo motivo:

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

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

Questa è solo la mia preferenza. Suppongo che dipenderà molto dal metodo chiamato e da come l'IDE aiuta lo sviluppatore a capire la firma.


1
Questo è il "lato negativo" di linguaggi tipicamente vaghi. Non puoi davvero imporre una firma senza una certa convalida. Non sapevo che potresti aggiungere nomi del genere in JS.
James P.

1
@JamesPoulson: Probabilmente sapevi di poterlo fare in JS e non te ne sei accorto. È tutto finito in JQuery: $.ajax({url:'', data:''})ecc. Ecc.
carne

Vero. Sembra insolito a prima vista ma è simile agli pseudo oggetti in linea che possono esistere in alcune lingue.
James P.

3

Trovo che questo sia il più semplice e facile da leggere:

enum Undo { ALLOW, PREVENT }

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

doSomething(Undo.ALLOW);

A MainMa non piace. Potremmo dover accettare di non essere d'accordo, oppure possiamo usare una soluzione che Joshua Bloch propone:

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
}

Ora, se mai aggiungi un Un.L.LITIT_UNDO, il tuo codice non verrà compilato se non implementi il ​​metodo createUndoBuffer (). E in doSomething () non esiste if (Undo.ALLOW == u). L'ho fatto in entrambi i modi e il secondo metodo è piuttosto pesante e un po 'difficile da capire quando l'enumerazione Undo si espande in pagine e pagine di codice, ma ti fa pensare. Di solito mi attengo al metodo più semplice per sostituire un semplice booleano con un enum di 2 valori fino a quando non ho motivo di cambiare. Quando aggiungo un terzo valore, utilizzo il mio IDE per "Trova-usi" e risolvo tutto.


2

Penso che la tua soluzione renda il tuo codice un po 'più leggibile, ma eviterei di definire una variabile aggiuntiva solo per rendere più chiara la chiamata della tua funzione. Inoltre, se si desidera utilizzare una variabile aggiuntiva, la contrassegnerei come costante se il linguaggio di programmazione la supporta.

Posso pensare a due alternative che non comportano una variabile aggiuntiva:

1. Usa un commento extra

doSomething(/* preventUndo */ true);

2. Usa un enum a due valori invece di booleano

enum Options
{
    PreventUndo,
    ...
}

...

doSomething(PreventUndo);

Puoi usare l'alternativa 2 se la tua lingua supporta enum.

MODIFICARE

Naturalmente, anche l'uso di argomenti con nome è un'opzione, se la tua lingua li supporta.

Per quanto riguarda la codifica aggiuntiva necessaria per gli enum, mi sembra davvero trascurabile. Invece di

if (preventUndo)
{
    ...
}

hai

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

o

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

E anche se è un po 'più di digitazione, ricorda che il codice viene scritto una volta e letto molte volte, quindi può essere utile digitare un po' di più ora per trovare un codice più leggibile sei mesi dopo.


2

Sono d'accordo con quello che ha detto @GlenPeterson:

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

ma anche l'interessamento sarebbe il seguente poiché mi sembra che ci siano solo due possibilità (vero o falso)

//Two methods    

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

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

2
Bella idea - non ci avevo pensato. Quando diventi più complicato come doSomething (String, String, String, boolean, boolean, boolean), le costanti con nome sono l'unica soluzione ragionevole. Bene, Josh Bloch suggerisce un oggetto factory e costruttore come in: MyThingMaker thingMaker = MyThingMaker.new (); thingMaker.setFirstString ( "Ciao"); thingMaker.setSecondString ( "ci"); ecc ... Cosa t = thingMaker.makeIt (); t.doSomething (); È solo molto più lavoro, quindi è meglio che ne valga la pena.
GlenPeterson,

Un problema con quest'ultimo approccio è che rende scomodo scrivere un metodo che utilizza doSomethingma consente al chiamante la scelta se consentire l'annullamento. Un rimedio potrebbe essere quello di avere un sovraccarico che accetta l'opzione booleana, ma anche versioni wrapper che chiamano la versione precedente con il parametro sempre vero o sempre falso.
supercat

@GlenPeterson Una fabbrica è una possibilità ed è possibile in Javascript (menzionata da OP).
James P.

2

Dal momento che stai chiedendo di javascript principalmente, usando coffeescript puoi avere un argomento chiamato come sintassi, super facile:

# 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)

compila a

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
});

Divertiti a http://js2coffee.org/ per provare le possibilità


Uso coffeeScript solo quando devo evitare la follia OOP di javascript. Questa è una bella soluzione che potrei usare quando codifico da solo, sarebbe difficile giustificare al collega che sto passando un oggetto invece di un valore booleano per motivi di leggibilità!
methodofaction

1

Solo per una soluzione meno convenzionale e poiché l'OP ha menzionato Javascript una possibilità è quella di utilizzare un array associativo per mappare i valori. Il vantaggio rispetto a un singolo booleano è che puoi avere tutti gli argomenti che desideri e non preoccuparti della loro sequenza.

var doSomethingOptions = new Array();

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

doSomething( doSomethingOptions );

// ...

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

Mi rendo conto che questo è un riflesso di qualcuno che proviene da un ambiente fortemente tipizzato e potrebbe non essere così pratico, ma considera questo per originalità.

Un'altra possibilità è avere un oggetto ed è anche possibile in Javascript. Non sono sicuro al 100% che questo sia sintatticamente corretto. Dai un'occhiata a modelli come Factory per ulteriore ispirazione.

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

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

1
Penso che questo possa essere scritto meglio nella notazione punto ( doSomethingOptions.PREVENTUNDO) anziché nella notazione di accesso all'array.
Paŭlo Ebermann,

1

Il focus della tua domanda e delle altre risposte è migliorare la leggibilità in cui viene chiamata la funzione, che è un focus con cui sono d'accordo. Eventuali linee guida specifiche, evento "nessun argomento booleano", dovrebbero sempre funzionare come mezzi a tal fine e non diventare e finire se stessi.

Penso che sia utile notare che questo problema è principalmente evitato quando il linguaggio di programmazione supporta argomenti denominati / argomenti di parole chiave, come in C # 4 e Python, o in cui gli argomenti del metodo sono interlacciati nel nome del metodo, come in Smalltalk o Objective-C.

Esempi:

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

0

Si dovrebbe evitare di passare variabili booleane come argomenti alle funzioni. Perché le funzioni dovrebbero fare una cosa alla volta. Passando la variabile booleana la funzione ha due comportamenti. Questo crea anche un problema di leggibilità per una fase successiva o per altri programmatori che tendono a vedere il tuo codice. Ciò crea anche problemi nel testare la funzione. Probabilmente in questo caso devi creare due casi di test. Immagina se hai una funzione che ha un'istruzione switch e cambia il suo comportamento in base al tipo di switch, quindi devi avere così tanti diversi casi di test definiti per questo.

Ogni volta che ci si imbatte in un argomento booleano per la funzione, devono modificare il codice in modo da non scrivere affatto argomenti booleani.


Quindi convertiresti una funzione con un argomento booleano in due funzioni che differiscono solo in una piccola parte del loro codice (dove l'originale avrebbe una if(param) {...} else {...})?
Paŭlo Ebermann,

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

Un buon compilatore per linguaggi di basso livello come C ++ ottimizzerà il codice macchina sopra la riga 2 come di seguito:

doSomething(true); 

quindi non importa in termini di prestazioni ma aumenterà la leggibilità.

Inoltre è utile utilizzare una variabile nel caso in cui diventerà variabile in un secondo momento e potrebbe accettare anche altri valori.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.