Che cos'è un oggetto di configurazione e perché utilizzarlo?

È un dolore dover cambiare i parametri di una funzione; devi cambiare ogni altra chiamata a quella funzione per evitare errori. Ma puoi aggirare questo usando solo un parametro: un oggetto di configurazione.


Cosa sembra

Ecco un esempio sciocco di una funzione per la creazione di un robot:

 function generateRobot (arms: int, personality: String): Robot var robot: Robot = new Robot (); per (var i: int = 0; i < arms; i++)  //create arm and add it to robot  if (personality == "evil")  robot.commands = "Destroy mankind.";  else  robot.commands = "Bake cookies."  return robot;  generateRobot(2, "evil");

Ora, ecco lo stesso esempio, usando un oggetto di configurazione:

 function generateRobot (conf: Object): Robot var robot: Robot = nuovo Robot (); per (var i: int = 0; i < conf.arms; i++)  //create arm and add it to robot  if (conf.personality == "evil")  robot.commands = "Destroy mankind.";  else  robot.commands = "Bake cookies."  return robot;  generateRobot(arms:2, personality:"evil");

Ho evidenziato le linee che richiedono il cambiamento; puoi vedere che non c'è molta differenza.


Perché preoccuparsi?

Quindi se non c'è praticamente alcuna differenza, perché dovremmo preoccuparci di farlo nel secondo modo? Dopo tutto, in realtà rende la funzione un po 'più difficile da usare; mentre prima che il nostro IDE potesse darci queste informazioni sui parametri la funzione prevista:

... ora può darci solo questo:

Supponiamo di voler aggiungere un paio di altri parametri: uno che specifica il materiale da utilizzare e un altro per specificare il colore del suo laser. Non è troppo difficile, in entrambi i casi:

 function generateRobot (arms: int, personality: String, material: String, laserColor: String): Robot var robot: Robot = new Robot (); per (var i: int = 0; i < arms; i++)  //create arm and add it to robot  if (personality == "evil")  robot.commands = "Destroy mankind.";  else  robot.commands = "Bake cookies."  switch (material)  case "wood": //wooden robot break; case "steel": default: //steel robot break;  robot.laser = new Laser(); robot.laser.color = laserColor; return robot;  generateRobot(2, "evil", "steel", "red");
 function generateRobot (conf: Object): Robot var robot: Robot = nuovo Robot (); per (var i: int = 0; i < conf.arms; i++)  //create arm and add it to robot  if (conf.personality == "evil")  robot.commands = "Destroy mankind.";  else  robot.commands = "Bake cookies."  switch (conf.material)  case "wood": //wooden robot break; case "steel": default: //steel robot break;  robot.laser = new Laser(); robot.laser.color = conf.laserColor; return robot;  generateRobot(arms:2, personality:"evil", material:"steel", laserColor:"red");

Finora, ancora non c'è molta differenza. Cosa succede se vuoi che i tuoi robot abbiano tutti i laser rossi per impostazione predefinita? Semplice ancora. Senza un oggetto di configurazione, è sufficiente modificare la firma del metodo (il funzione linea), e quindi è possibile rimuovere l'ultimo argomento dalla chiamata della funzione:

 function generateRobot (arms: int, personality: String, material: String, laserColor: String = "red"): Robot // questo è tutto lo stesso generateRobot (2, true, "steel"); // Ho rimosso l'ultimo argomento

Con un oggetto di configurazione, è un po 'più complicato, anche se non molto:

 function generateRobot (conf: Object): Robot if (! conf.laserColor) conf.laserColor = "red";  var robot: Robot = new Robot (); per (var i: int = 0; i < conf.arms; i++)  //create arm and add it to robot  if (conf.personality == "evil")  robot.commands = "Destroy mankind.";  else  robot.commands = "Bake cookies."  switch (conf.material)  case "wood": //wooden robot break; case "steel": default: //steel robot break;  robot.laser = new Laser(); robot.laser.color = conf.laserColor; return robot;  generateRobot(arms:2, personality:"evil", material:"steel"); //I removed the last argument

Va bene. Ora immagina di scoprire che stai impostando quasi tutti i tuoi robot a essere malvagi (voglio dire, perché no?), Quindi in realtà è una specie di sofferenza scrivere sempre "male" come parametro. Naturalmente, vuoi impostare "il male" come predefinito - ma tu non vuoi impostare un materiale predefinito.

L'unico modo per farlo, con un set regolare di parametri di funzione, è quello di cambiare l'ordine di personalità e Materiale parametri:

 function generateRobot (arms: int, material: String, personality: String = "evil", laserColor: String = "red"): Robot 

Ah, ma ora devi cambiare l'ordine degli argomenti su ogni singola chiamata di funzione!

 generateRobot (2, "evil", "steel"); //non lavora più

Un oggetto di configurazione non ti dà questo problema. Controlla:

 function generateRobot (conf: Object): Robot if (! conf.laserColor) conf.laserColor = "red";  if (! conf.personality) conf.personality = "evil" // questo è tutto lo stesso generateRobot (arms: 2, material: "steel"); // nessun parametro "personalità"? nessun problema!

Neat! Tutto il tuo vecchio generateRobot () le chiamate alle funzioni continueranno a funzionare, ma è possibile creare nuove chiamate che non si preoccupino di specificare personalità.

Puoi anche decidere di sbarazzarti di personalità parametro del tutto:

 function generateRobot (conf: Object): Robot if (! conf.laserColor) conf.laserColor = "red";  if (! conf.personality) conf.personality = "evil" var robot: Robot = new Robot (); per (var i: int = 0; i < conf.arms; i++)  //create arm and add it to robot  robot.commands = "Destroy mankind."; switch (conf.material)  case "wood": //wooden robot break; case "steel": default: //steel robot break;  robot.laser = new Laser(); robot.laser.color = conf.laserColor; return robot; 

La versione precedente della funzione non fa riferimento a conf.personality a tutti - ma non riceverai un errore se hai ancora chiamate come questa:

 generateRobot (arms: 2, personality: "evil", material: "steel");

Ovviamente, potresti avere alcuni utenti confusi se hai chiamate come questa:

 generateRobot (arms: 2, personality: "good", material: "steel");

... poiché tutti i robot ora sono malvagi. Ma almeno il codice verrà compilato.

Per lo stesso motivo, puoi cambiare l'ordine degli argomenti senza che questo sia importante, e persino aggiungere nuovi parametri che non fanno ancora nulla:

 generateRobot (material: "steel", laserColor: "green", arms: 2, voice: "Mr. T");

Rendere più facile impostare i valori predefiniti

Il codice per l'impostazione dei valori predefiniti è facile da comprendere fino ad ora, ma sarà molto fastidioso estendere se abbiamo bisogno di avere molti parametri:

 if (! conf.laserColor) conf.laserColor = "red";  if (! conf.personality) conf.personality = "evil"

Scriviamo un codice più generale per affrontarlo:

 var defaults: Object = laserColor: red, personality: "evil" for (chiave var: String in default) if (! conf [key]) conf [key] = defaults [chiave]; 

Quello per il ciclo potrebbe essere un po 'confuso, quindi lo analizzerò. Innanzitutto, guarda questo:

 for (chiave var: String in default) trace (chiave); 

Questo è un per ... in loop, che produrrà i nomi delle chiavi all'interno di predefinito oggetto:

 personalità laserColor

Quindi, guarda questa riga:

 traccia (default [ "laserColor"]);

Questo uscirà rosso - è lo stesso della scrittura traccia (defaults.laserColor).

A seguito di ciò, guarda questo esempio:

 esempio var: Object = demo: "test"; trace (ad esempio [ "demo"]); trace (ad esempio [ "foo"]);

Cosa pensi che uscirà?

Bene, Esempio [ "demo"] equivale a example.demo, quale è uguale a "test". Ma example.foo non esiste, quindi Esempio [ "foo"] tornerà nullo. Ciò significa che !Esempio [ "foo"] (notare il punto esclamativo) sarà equivalente a vero.

Metti tutto insieme e dovresti essere in grado di capire perché questo codice funzioni:

 var defaults: Object = laserColor: red, personality: "evil" for (chiave var: String in default) if (! conf [key]) conf [key] = defaults [chiave]; 

Dammi un urlo nei commenti se hai bisogno di una mano!

Voglio di più!

Per una versione ancora più veloce, prova questo:

 function generateRobot (conf: Object = null): Robot var conf: Object = conf || ; var defaults: Object = laserColor: red, personality: "evil" for (chiave var: String in default) conf [key] = conf [chiave] || default [key]; 

Il cambio di Linea 1 (e nuova Linea 2) significa che anche il conf l'oggetto stesso è facoltativo, quindi puoi semplicemente chiamare generateRobot (). (Ovviamente, dovrai cambiare il codice per gestire i valori che al momento non hanno i valori predefiniti).


Aiutare l'IDE ad aiutarti

Come accennato in precedenza, l'IDE non può fornire alcun suggerimento su quali parametri una funzione è in attesa, se tale funzione utilizza un oggetto di configurazione. Questo è un grosso inconveniente, poiché può rendere il tuo codice davvero difficile da usare; devi ricordare quali parametri vanno nel conf oggetto, così come tutti i loro nomi e tipi.

Ma possiamo ancora visualizzare queste informazioni al programmatore quando è necessario; dobbiamo solo farlo manualmente, in questo modo:

 / ** * Genera un robot, in base ai parametri forniti. * @param conf Oggetto di configurazione. Prevede: * armi (int) Numero di braccia robot dovrebbe avere. * personalità (stringa) Personalità del robot. Può essere "cattivo" o "buono". Predefinito a "cattivo". * materiale (stringa) Da cosa deve essere fatto il robot. Può essere "acciaio" o "legno" in questo momento. * laserColor (String) Colore del laser del robot. Il valore predefinito è "rosso". * voice (String) Stile vocale del robot. Attualmente non implementato. * @return Il robot finito. * / function generateRobot (conf: Object): Robot //

Ora, se inizio a scrivere una chiamata a questa funzione in FlashDevelop (il mio IDE preferito), vedo questo:

Certo, è un po 'un problema tenerlo aggiornato manualmente, ma in molti casi ne vale la pena.


Conclusione

Non sto sostenendo che dovresti usare un oggetto di configurazione per ogni singola funzione crei d'ora in poi; pensalo come un altro strumento utile nel tuo arsenale.

Personalmente, lo trovo un modello particolarmente utile ogni volta che sto costruendo la prima bozza di alcune serie di classi che hanno tutte bisogno di lavorare insieme. La maggiore flessibilità di a conf mi dà molta più flessibilità, liberandomi per comprimere tutte le diverse funzioni e cambiare il modo in cui si chiamano, senza preoccuparsi di rompere il codice inserendo o rimuovendo un parametro.

Ricorda i benefici:

  • È facile aggiungere e rimuovere parametri (alle estremità).
  • È facile impostare valori predefiniti.
  • Non devi preoccuparti dell'ordine dei parametri.

Ci sono tuttavia degli svantaggi nell'usare oggetti semplici come quelli che ho, specialmente se lo fai in un progetto che ha superato la fase di prototipazione. Dai un'occhiata agli ottimi commenti qui sotto per maggiori dettagli!