Parametri opzionali o costruttori sovraccaricati

27

Sto implementando un DelegateCommand , e quando stavo per implementare il / i costruttore / i, sono arrivato con le seguenti due scelte progettuali:

1: avere più costruttori sovraccaricati

public DelegateCommand(Action<T> execute) : this(execute, null) { }

public DelegateCommand(Action<T> execute, Func<T, bool> canExecute)
{
    this.execute = execute;
    this.canExecute = canExecute;
}

2: con un solo costruttore con un parametro facoltativo

public DelegateCommand(Action<T> execute, Func<T, bool> canExecute = null)
{
    this.execute = execute;
    this.canExecute = canExecute;
}

Non so quale usare perché non so quali possibili vantaggi / svantaggi vengano con uno dei due modi proposti. Entrambi possono essere chiamati in questo modo:

var command = new DelegateCommand(this.myExecute);
var command2 = new DelegateCommand(this.myExecute, this.myCanExecute);

Qualcuno può indicarmi la giusta direzione e dare un feedback?

    
posta Thomas Flinkow 27.03.2018 - 09:04
fonte

3 risposte

23

Preferisco più costruttori rispetto ai valori predefiniti e personalmente non mi piace il tuo esempio di due costruttori, dovrebbe essere implementato in modo diverso.

Il motivo dell'utilizzo di più costruttori è che il principale può semplicemente verificare se tutti i parametri non sono nulli e se sono validi mentre altri costruttori possono fornire valori predefiniti per quello principale.

Tuttavia, nei tuoi esempi non vi è alcuna differenza tra di loro perché anche il costruttore secondario passa un null come valore predefinito e il costruttore principale deve conoscere anche il valore predefinito. Penso che non dovrebbe.

Ciò significa che sarebbe più pulito e meglio separato se implementato in questo modo:

public DelegateCommand(Action<T> execute) : this(execute, _ => true) { }

public DelegateCommand(Action<T> execute, Func<T, bool> canExecute)
{
    this.execute = execute ?? throw new ArgumentNullException(..);
    this.canExecute = canExecute ?? throw new ArgumentNullException(..);
}

nota che _ => true è passato al costruttore principale che ora controlla anche tutti i parametri per null e non si preoccupa di alcun valore predefinito.

Il punto più importante è tuttavia l'estensibilità. Più costruttori sono più sicuri quando è possibile estendere il codice in futuro. Se aggiungi altri parametri obbligatori e quelli facoltativi devono arrivare alla fine, interromperai tutte le implementazioni correnti. Puoi rendere il vecchio costruttore [Obsolete] e informare gli utenti che verrà rimosso, dando loro il tempo di migrare alla nuova implementazione senza rompere istantaneamente il loro codice.

D'altro canto rendere troppi parametri facoltativi potrebbe confondere anche perché se alcuni di essi sono richiesti in uno scenario e facoltativi in un altro, sarà necessario studiare la documentazione invece di scegliere il giusto costruttore semplicemente guardando il suo i parametri.

    
risposta data 27.03.2018 - 09:18
fonte
17

Considerando che l'unica cosa che stai facendo nel costruttore è l'assegnazione semplice, la singola soluzione di costruzione potrebbe essere una scelta migliore nel tuo caso. L'altro costruttore non fornisce funzionalità aggiuntive ed è chiaro dal design del costruttore con due parametri che non è necessario fornire il secondo argomento.

I costruttori multipli hanno senso quando si costruisce un oggetto da diversi tipi. In tal caso, i costruttori sono una sostituzione di un factory esterno perché elaborano i parametri di input e li formattano in una rappresentazione di proprietà interna corretta della classe che viene costruita. Ciò non accade tuttavia nel tuo caso, quindi perché un singolo costruttore dovrebbe essere più che sufficiente.

    
risposta data 27.03.2018 - 09:20
fonte
2

Penso che ci siano due casi diversi per i quali ogni approccio può brillare.

In primo luogo, quando abbiamo semplici costruttori (che di solito è il caso, nella mia esperienza), considererei gli argomenti opzionali per brillare.

  1. Riducono al minimo il codice che deve essere scritto (e quindi anche quello che deve essere letto).
  2. Puoi assicurarti che la documentazione sia in un posto e non sia ripetuta (il che è male perché apre un'area extra che potrebbe diventare obsoleta).
  3. Se hai molti argomenti opzionali, puoi evitare di avere un insieme di combinazioni di costruttori molto confuso. Diamine, anche con solo 2 argomenti opzionali (non correlati tra loro), se si desiderava costruttori separati e sovraccarichi, si dovrebbero avere 4 costruttori (versione senza alcuna versione con ciascuno e versione con entrambi). Questo ovviamente non si adatta bene.

Buuuut, ci sono casi in cui gli argomenti opzionali nei costruttori semplicemente rendono le cose chiaramente più confuse. L'ovvio esempio è quando questi argomenti opzionali sono esclusivi (cioè, non possono essere usati insieme). Avere sovraccaricato i costruttori che consentono solo le combinazioni di argomenti effettivamente valide garantirebbe l'applicazione del tempo di compilazione di questo vincolo. Detto questo, dovresti evitare anche di incontrare questo caso (ad esempio, con più classi che ereditano da una base, dove ogni classe esegue il comportamento esclusivo).

    
risposta data 27.03.2018 - 22:07
fonte

Leggi altre domande sui tag