Un parametro opzioni vs funzioni concatenate per l'inizializzazione dell'oggetto?

2

Quali vantaggi oggettivi concreti hanno le funzioni concatenate rispetto a un parametro opzioni per l'inizializzazione dell'oggetto?

Che cosa intendo? Come esempio, esiste una libreria chiamata dat.GUI che utilizza lo stile di funzione concatenato per impostare le cose. Ad esempio un cursore a intervallo semplice ha 4 o 5 parametri.

/**
 * @param {object} object The object with a property you want a GUI for
 * @param {string} property The name of the property to make a GUI for
 * @param {number} min The minimum value
 * @param {number} max The maximum value
 * @param {number} [step] An optional step
 */
gui.add(object, property, min, max, opt_step)

Ma poi ci sono diverse impostazioni opzionali. Li imposti chiamando le funzioni concatenate. Ad esempio name(someName) imposta l'etichetta mostrata sulla GUI. Il valore predefinito è il nome della proprietà. onChange(fn) imposta un callback quando il valore cambia. listen() indica alla GUI di controllare le modifiche alla proprietà.

Quindi, se vuoi impostare tutti quelli che potresti scrivere

gui.add(someObject, 'someProp', 10, 20).name('foo').onChange(someFunc).listen();

Dove come gui.add ha preso un oggetto opzioni come input potresti scrivere qualcosa come

gui.add({
  target: someObject,
  property: 'someProp',
  min: 10,
  max: 20,
  name: 'foo',
  onChange: someFunc,
  listen: true,
});

Questo è un 6 di una mezza dozzina di un altro tipo di situazione, in quanto in entrambi gli stili va bene o uno stile ha vantaggi concreti rispetto all'altro.

In cima alla mia testa

  • le funzioni concatenate sono più concise ma il parametro delle opzioni è più leggibile. Vedo min: 10 e so che 10 è min e non width o size o numItems ecc. Al contrario devo specificare tutti i parametri.

  • i parametri delle opzioni sembrano più flessibili. Può più facilmente fare qualcosa come

    gui.add(Object.assign({}, globalOptions, localOptions));
    
  • Il completamento del codice sembra un disastro.

    Se esistono definizioni sia per le funzioni che per i tipi di parametri incluso il parametro options, allora sembra che sia simile? Vedere tutte le opzioni potrebbe essere utile ma il completamento dopo gui.add(...). dovrebbe mostrare tutte le funzioni concatenabili in modo che sia probabilmente la stessa?

  • I parametri delle opzioni sono più probabili?

    Con questo intendo se giu.add richiede 5 parametri in un ordine specifico, se in seguito risulta che il parametro # 3 non è importante ma # 4 è quindi troppo tardi, non è possibile scambiare facilmente l'ordine e fare quale era il parametro n. 3 in quanto tutti gli utenti dovevano cambiare il loro codice mentre con i parametri delle opzioni si può?

  • In un linguaggio strongmente tipizzato se ci sono molte opzioni allora l'oggetto options stesso potrebbe diventare grande e complicato (molta inizializzazione per tutti i campi) mentre con le funzioni concatenate si creano solo le cose necessarie. Ma questo non si adatta a JavaScript, quindi non è un vantaggio lì?

  • Le funzioni concatenate possono essere richiamate successivamente individualmente

    In altre parole

    const control = gui.add(...);
    ...20 seconds later...
    control.name('foo');
    

    Per lo stile di opzioni avresti bisogno di qualcosa come setOptions(options) metodo che potrebbe non essere cattivo ma potrebbe avere strane limitazioni come certe opzioni possono essere specificate solo al momento della creazione.

Qualcos'altro che mi manca? C'è una ragione oggettiva per scegliere l'una rispetto all'altra come in "se la situazione X usa funzioni concatenate, se la situazione Y usa un oggetto opzioni" o è principalmente solo un problema di stile?

    
posta gman 29.08.2018 - 21:25
fonte

2 risposte

2

Quando tutte le funzioni concatenabili dell'oggetto sono - in sostanza - solo setter per parametri individuali (come nel tuo esempio), allora le differenze semantiche tra i due approcci sono quasi trascurabili. In questo caso, l'utilizzo di parametri facoltativi è più semplice, più idiomatico e quindi preferibile.

Tuttavia, il concatenamento delle funzioni (o concatenamento dei metodi ) ha più senso nel contesto degli oggetti builder in cui i metodi avere semantica più complessa. Ad esempio, pensa a ControlBuilder con un'interfaccia fluente , in cui puoi aggiungere successivamente il testo dell'etichetta chiamando un metodo come AppendLine più di una volta. Oppure, pensa a metodi in cui l'ordine specifico delle chiamate fa la differenza. Ci sono molti esempi per questo nell'articolo di Wikipedia sulle interfacce fluenti. Questo è qualcosa che non puoi raggiungere con i parametri opzionali.

    
risposta data 28.10.2018 - 23:44
fonte
0

Per lo più ho visto lo schema della funzione concatenata (di solito chiamato il modello di build in lingue come Java dove oggetti anonimi, come il tipo che stai proponendo come parametro delle opzioni, sono più rari / non idiomatici / impossibili da creare.

In JavaScript, ho il parametro delle opzioni più spesso, ma ciò non significa che sia migliore.

Il tuo confronto tra i due è piuttosto approfondito. Una cosa che vorrei aggiungere: con il pattern builder, considera che può rendere più difficile la convalida delle opzioni in alcuni scenari. Ad esempio, se desideri consentire la specifica di% enumerato% co_de solo se è stato attivato o disattivato OptionB togglebile.

Come fai a impedire agli utenti della tua API di fare qualcosa del tipo,

builder.disableOptionA().setOptionB(OptionB.SOME_VALUE).build();

È possibile farlo, ma farlo sembra implicare un costruttore multistato che può diventare piuttosto complicato. Altrimenti, la gestione degli errori deve essere eseguita nel metodo OptionA (che potrebbe sembrare meno elegante per l'utente). Come utente API, mi piace sentirmi al sicuro quando concatenando metodi come questo.

Detto questo, la convalida delle opzioni è un problema anche per il pattern dei parametri delle opzioni. Almeno con il modello di builder, è possibile applicare le regole sulle opzioni man mano che procedi.

Hai considerato un approccio ibrido? Avere il metodo build accetta e gui.add() oggetto che può essere costruito 'manualmente', ma anche fornire un oggetto Options per comodità (o inconveniente, a seconda di chi si chiede: P).

Quindi sono permessi entrambi i seguenti:

gui.add(new Options(optionAVal, optionBVal));
gui.add(
    OptionsBuilder.options()
    .optionA(optionAVal)
    .optionB(optionBVal)
    .build()
);
    
risposta data 29.08.2018 - 22:01
fonte

Leggi altre domande sui tag