Ce este un obiect de configurare și de ce să-l folosim?

Este o durere să trebuiască să modificați parametrii unei funcții; trebuie să schimbați fiecare apel la această funcție pentru a evita erorile. Dar puteți obține acest lucru folosind un singur parametru: un obiect de configurare.


Cum arata

Iată un exemplu prost de funcție pentru crearea unui robot:

 funcția generateRobot (arme: int, personalitate: String): Robot robot var: Robot = Robot nou (); pentru (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");

Acum, iată același exemplu, folosind un obiect de configurare:

 funcția generateRobot (conf: Object): robot robot var: robot = robot nou (); pentru (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");

Am subliniat liniile care necesită schimbare; puteți vedea că nu există prea multe diferențe.


De ce sa te deranjezi?

Deci, dacă nu există nici o diferență, de ce ne-ar deranja să o facem pe a doua cale? La urma urmei, aceasta face ca functia sa fie mai greu de folosit; întrucât înainte ca IDE-ul nostru să ne ofere aceste informații despre parametrii funcției așteptate:

... acum ne poate da numai acest lucru:

Să presupunem că doriți să adăugați și câțiva parametri: unul specificând materialul utilizat și altul specificând ce culoare să fie laserul. Nu este prea greu, în ambele cazuri:

 funcția generateRobot (arme: int, personalitate: String, material: String, laserColor: String): Robot robot var: Robot = Robot nou; pentru (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");
 funcția generateRobot (conf: Object): robot robot var: robot = robot nou (); pentru (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");

Până în prezent, încă nu prea este o diferență. Ce se întâmplă dacă doriți ca roboții dvs. să aibă lasere roșii în mod implicit? Simplu din nou. Fără un obiect de configurare, trebuie doar să schimbați semnătura metodei ( funcţie line) și apoi puteți elimina ultimul argument din apelul funcției:

 funcția generateRobot (arme: int, personalitate: String, material: String, laserColor: String = "roșu"): Robot // totul este același generateRobot (2, true; // Am eliminat ultimul argument

Cu un obiect de configurare, este puțin mai complicat - deși nu prea mult:

 funcția generateRobot (conf: Object): Robot if (! conf.laserColor) conf.laserColor = "roșu";  robot var: Robot = Robot nou (); pentru (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

Bine. Acum, să presupunem că veți găsi că aproape toți roboții dvs. sunt răi (vreau să spun, de ce nu?), Deci este oarecum o durere de a scrie "rău" ca parametru de fiecare dată. Bineînțeles, doriți să setați "rău" ca implicit - dar tu nu face doriți să setați un material implicit.

Singurul mod în care puteți face acest lucru, cu un set regulat de parametri funcționali, este de a comuta ordinea personalitate și material parametri:

 funcția generateRobot (arme: int, material: String, personalitate: String = "rău", laserColor: String = "roșu"): Robot 

Ah, dar acum trebuie să schimbați ordinea argumentelor rotunde pentru fiecare apel de funcție!

 generateRobot (2, "rău", "oțel"); // nu mai funcționează

Un obiect de configurare nu vă dă această problemă. Verifică:

 funcția generateRobot (conf: Object): Robot if (! conf.laserColor) conf.laserColor = "roșu";  if (conf.personalitate) conf.personalitate = "rău" // acest lucru este același generateRobot (arme: 2, material: "oțel"); // nu există parametru de "personalitate"? nici o problema!

Neat! Toți bătrânii tăi generateRobot () apelurile funcționale vor continua să funcționeze, dar puteți crea noi apeluri care nu deranjează specificarea personalitate.

Puteți chiar decide să scape de personalitate parametru total:

 funcția generateRobot (conf: Object): Robot if (! conf.laserColor) conf.laserColor = "roșu";  dacă (! conf.personalitate) conf.personalitate = "rău" robot robot: Robot = Robot nou (); pentru (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; 

Versiunea de mai sus a funcției nu se referă la conf.personality la toate - dar nu veți primi o eroare dacă aveți în continuare apeluri de genul:

 generateRobot (arme: 2, personalitate: "rău", material: "oțel");

Bineînțeles, este posibil să primiți câțiva utilizatori confuzi dacă aveți apeluri de genul:

 generateRobot (arme: 2, personalitate: "bun", material: "oțel");

... deoarece toți roboții sunt acum răi. Dar cel puțin codul se va compila.

Din același motiv, poți schimba ordinea argumentelor fără să conteze deloc și chiar să adaugi noi parametri care încă nu fac nimic:

 generateRobot (material: "oțel", laserColor: "verde", brațe: 2, voce: "Domnul T");

Este mai ușor să setați valorile prestabilite

Codul pentru setarea valorilor implicite este ușor de înțeles până acum, dar va fi foarte enervant să se extindă dacă trebuie să avem o mulțime de parametri:

 dacă (! conf.laserColor) conf.laserColor = "roșu";  dacă (! conf.personalitate) conf.personalitate = "rău"

Să scriem un cod mai general pentru a face față acestei situații:

 var implicit: Object = laserColor: roșu, personalitate: "rău" pentru (var var: String în defaults) if (conf [cheie]) conf [key] = defaults [key]; 

Acea pentru bucla poate fi puțin confuză, așa că o voi rupe. În primul rând, uitați-vă la acest lucru:

 pentru (var var: String în defaults) trace (cheie); 

Acesta este un pentru ... in buclă, care va afișa numele cheilor din interiorul lui Mod implicit obiect:

 personalitatea laserColor

Apoi, uita-te la această linie:

 urme (defaults [ "laserColor"]);

Aceasta va ieși roșu - este la fel ca scrisul trace (defaults.laserColor).

În urma acestui aspect, uitați-vă la acest exemplu:

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

Ce credeți că va produce acest lucru?

Bine, exemplu [ "demo"] este la fel ca example.demo, care este egal "Test". Dar example.foo nu există, deci exemplu [ "foo"] va reveni nul. Aceasta înseamnă că !exemplu [ "foo"] (notează semnul exclamării) va fi echivalentă cu Adevărat.

Puneți-le pe toate împreună și ar trebui să înțelegeți de ce funcționează acest cod:

 var implicit: Object = laserColor: roșu, personalitate: "rău" pentru (var var: String în defaults) if (conf [cheie]) conf [key] = defaults [key]; 

Dă-mi un strigăt în comentariile dacă ai nevoie de o mână!

Vreau mai mult!

Pentru o versiune mai rapidă, încercați acest lucru:

 funcția generateRobot (conf: Object = null): Robot var conf: Object = conf || ; var defaults: Object = laserColor: roșu, personalitate: "rău" pentru (var var: String în defaults) conf [key] = conf [key] || implicite [cheie]; 

Schimbarea în rândul 1 (și noua linie 2) înseamnă că și conf obiectul în sine este opțional, astfel încât să puteți apela doar generateRobot (). (Desigur, va trebui să schimbați codul pentru a face față valorilor care în prezent nu au valori implicite.)


Ajutând IDE-ul să vă ajute

După cum am menționat mai sus, IDE nu vă poate oferi sfaturi despre ce parametri se așteaptă o funcție, dacă această funcție utilizează un obiect de configurare. Acesta este un dezavantaj major, deoarece vă poate face foarte greu să utilizați codul; trebuie să vă amintiți ce parametri intră în conf obiect, precum și toate numele și tipurile acestora.

Însă putem afișa aceste informații coderului când este necesar; trebuie doar să facem acest lucru manual, așa cum este cazul:

 / ** * Generați un robot, pe baza parametrilor. * @param conf Obiect de configurare. Se așteaptă ca: * brațele (int) Numărul robotului de arme să aibă. * personalitate (String) Personalitatea robotului. Poate fi "rău" sau "bun". Implicit la "rău". * material (String) Ce trebuie făcut din robot. Poate fi "oțel" sau "lemn" în acest moment. * laserColor (String) Culoarea laserului robotului. Implicit la "roșu". * voce (String) Stilul vocal al robotului. În prezent, nu este implementat. * @return Robotul terminat. * / funcția generateRobot (conf: Object): Robot //

Acum, dacă încep să scriu un apel la această funcție în FlashDevelop (IDE-ul meu de alegere), văd acest lucru:

Sigur, este un pic de durere ca acest lucru să fie actualizat manual, dar în multe cazuri merită.


Concluzie

Nu pretind că ar trebui să folosiți un obiect de configurare fiecare funcție creați de acum încolo; gândiți-vă doar la aceasta ca la un alt instrument util în arsenalul dvs..

Personal, mi se pare un model deosebit de util ori de câte ori construiesc primul proiect al unui ansamblu de clase care trebuie să lucreze împreună. Flexibilitatea adăugată a conf îmi oferă mult mai multă flexibilitate, eliberându-mă pentru a zip în jurul tuturor funcțiilor diferite și pentru a schimba modul în care se numește unii pe alții, fără să vă faceți griji despre ruperea codului prin introducerea sau eliminarea unui parametru.

Rețineți avantajele:

  • Este ușor să adăugați și să eliminați parametrii (la fiecare capăt).
  • Este ușor să setați valorile implicite.
  • Nu trebuie să vă faceți griji cu privire la ordinea parametrilor.

Există neajunsuri în utilizarea obiectelor simple cum ar fi eu, totuși - mai ales dacă faceți acest lucru într-un proiect care a trecut de etapa prototipului. Consultați comentariile minunate de mai jos pentru mai multe detalii!

Cod