Qual è l'opzione generale sul passaggio di un parametro booleano in un metodo o costruttore nei linguaggi OOP? [chiuso]

3

Mi sono imbattuto in questo problema durante il mio secondo colloquio di lavoro. L'intervistatore tecnico ha detto più volte che i booleani non sono ok per essere passati come parametri nei metodi, piuttosto trovare altri costrutti (Enum) per sbarazzarsi dei booleani.

Qual è l'opinione generale su questo argomento?

    
posta Adrian Muntean 28.02.2018 - 17:04
fonte

5 risposte

13

Enh. In genere è spiacevole passare in un booleano che governa il comportamento - "Se X fa questa altra roba". La funzione tende quindi a non avere una singola responsabilità focalizzata che rende più difficile testare, più difficile da riutilizzare, più difficile da mantenere, ecc.

Ed è generalmente di cattivo gusto nella maggior parte delle lingue avere solo un parametro booleano perché nel sito di chiamata si vede solo function("abc", true); . Cosa diavolo significa true qui? Alcune persone sostengono invece le enumerazioni (o le costanti statiche). Alcune persone sostengono invece le funzioni separate. Questo è ovviamente peggiorato quando c'è un gruppo di booleani ed è difficile ricordare l'ordine. Le lingue che consentono i parametri etichettati in stile function("abc", recursive: true) possono attenuarle un po '.

Ma francamente, ci sono molti casi d'uso in cui i parametri booleani sono semplici e chiari. E l'impatto dell'utilizzo di parametri booleani è così lieve che il dogmatico "non avrai parametri bool" sembra sciocco.

    
risposta data 28.02.2018 - 17:17
fonte
4

In un mondo basato sul codice , con metodi espliciti che le cose do sono preferite:

class ControlDerivedUIClass
{ 
   void enable(); 
   void disable(); 
} 

Tuttavia, in un mondo basato sui dati , quando leggi le impostazioni da un archivio dati esterno, come un file, potrebbe avere più senso consentire ai tuoi oggetti di essere più dati guidato, come in:

class ControlDerivedUIClass
{ 
   void enable( bool value ); 
} 
    
risposta data 28.02.2018 - 17:40
fonte
3

Potresti avere questo:

Squirt squirt = new Squirt(true);                         // WTF does "true" mean?

O potresti avere questo:

Squirt squirt = new Squirt(WITH_AGGRESSIVE_FROBINATION);  // Ah! I get it!

Ma c'è una terza via:

interface Frobinator { ... }

Frobinator f = new AggressiveFrobinator();
Squirt squirt = new Squirt(f);

Questo è un esempio di delega . L'oggetto f diventa il delegato dell'oggetto squirt . Quando squirt deve eseguire la frobination, richiede all'oggetto f di eseguire il lavoro effettivo.

La delega di una responsabilità come questa è probabilmente una soluzione eccessivamente ingegnerizzata per alcuni problemi. Costringe il chiamante a scrivere più codice, ma alla fine è la soluzione più flessibile e potente.

  1. Ti offre un modo per estendere la classe Squirt senza modificarne il codice. È possibile definire e testare nuove modalità di frobinizzazione senza toccare alcuna vecchia riga di codice. Ad esempio, la classe Squirt può essere aperta per l'estensione, ma chiusa per la modifica .

  2. I chiamanti potenzialmente possono definire i loro metodi personalizzati di frobinizzazione.

  3. Rende la tua classe Squirt più testabile: non è più necessario testare separatamente ciò che squirt.x() fa con frobination aggressivo e testare cosa squirt.x() fa con la normale frobination, AND prova cosa squirt.x() fa con qualche nuovo tipo di frobination ... Ora puoi sostituire tutti quelli con un solo test che si assicura che squirt.x() interagisca correttamente con il suo frobinator. (Nota, questa è fondamentalmente l'idea centrale di test dell'unità .)

risposta data 01.03.2018 - 19:02
fonte
2

Penso che questo si applichi agli inte e agli archi e ai booleani. Questi sono tutti tipi di dati primitivi nel dominio dei linguaggi di programmazione.

Quando si passa un tipo primitivo come parametro, come lettore di quel codice non si sa quale potrebbe essere il significato di true vs. false, a meno che non si stia utilizzando un linguaggio che offre l'assegnazione dei parametri, come in% codice%. Devi cercare la firma dei metodi per vedere il nome del parametro per avere un significato.

In generale, preferiremmo generalmente vedere astrazioni e tipi orientati al dominio. Otteniamo questi usando enumerazioni, classi e amp; structs, etc: dando loro nomi e operazioni significativi. Con quelli il codice è più auto-documentante.

    
risposta data 28.02.2018 - 17:15
fonte
0

In primo luogo, questo non ha nulla a che fare con la programmazione orientata agli oggetti. Hai esattamente lo stesso problema con le normali chiamate alle vecchie funzioni, e il problema è che se un parametro è solo "vero" o "falso", allora il lettore del codice non ha la possibilità di capire cosa fa il codice, eccetto se è l'unico parametro di una funzione opportunamente denominata: object- > setVisible (true) è assolutamente soddisfacente.

Ci sono lingue in cui i parametri sono nominati in una chiamata. Ad esempio, object.setOptions (visible: true, opaque: false, animated: true) è di nuovo soddisfacente. Ma object.setOptions (true, false, true) è un grosso problema, perché solo leggendo quella riga di codice non ho idea di cosa stia succedendo. Non so quali sono i parametri e sicuramente non ho idea del loro ordine. In questo caso, usando enum e chiamando object.setOptions (eVisible, eTransparent, eAnimated) va di nuovo bene. Enum, non costanti impostate su valori booleani.

Quel che è peggio è che non solo non so cosa significhi il tuo codice, il compilatore può anche non aiutarti se sbagli. object.setOptions (false, true, true) si compila bene e dà risultati completamente sbagliati. si spera che object.setOptions (eTransparent, eVisible, eAnimated) non venga compilato, in modo da poter risolvere immediatamente il problema.

    
risposta data 02.03.2018 - 14:20
fonte

Leggi altre domande sui tag