Wat is een configuratie-object en waarom zou u het gebruiken?

Het is lastig om de parameters van een functie te moeten veranderen; je moet elke andere oproep naar die functie veranderen om fouten te voorkomen. Maar u kunt dit omzeilen door slechts één parameter te gebruiken: een configuratieobject.


Hoe het eruit ziet

Hier is een dom voorbeeld van een functie voor het maken van een robot:

 functie generateRobot (arms: int, personality: String): Robot var robot: Robot = nieuwe robot (); for (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");

Nu, hier is hetzelfde voorbeeld, met behulp van een configuratie-object:

 functie generateRobot (conf: Object): Robot var robot: Robot = nieuwe robot (); for (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");

Ik heb de lijnen gemarkeerd die moeten worden gewijzigd; je kunt zien dat er niet veel verschil is.


Waarom zou je je drukmaken?

Dus als er nauwelijks verschil is, waarom zouden we het dan op de tweede manier doen? Het maakt de functie eigenlijk een beetje moeilijker om te gebruiken; overwegende dat onze IDE in staat zou zijn om ons deze informatie te geven over de parameters die de functie verwachtte:

... nu kan het ons alleen dit geven:

Stel dat u nog een paar parameters wilt toevoegen: de ene specificeert het te gebruiken materiaal en de andere om op te geven welke kleur de laser moet zijn. Dat is niet zo moeilijk, in beide gevallen:

 functie generateRobot (arms: int, personality: String, material: String, laserColor: String): Robot var robot: Robot = nieuwe robot (); for (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");
 functie generateRobot (conf: Object): Robot var robot: Robot = nieuwe robot (); for (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");

Tot nu toe, nog steeds niet echt een verschil. Wat als je wilt dat je robots standaard allemaal rode lasers hebben? Eenvoudig weer. Zonder een configuratieobject hoeft u alleen de methodehandtekening te wijzigen (de functie regel) en dan kunt u het laatste argument uit de functieaanroep verwijderen:

 functie generateRobot (arms: int, personality: String, material: String, laserColor: String = "red"): Robot // dit is allemaal hetzelfde generateRobot (2, true, "steel"); // Ik heb het laatste argument verwijderd

Met een configuratie-object is het een beetje lastiger - maar niet veel:

 functie generateRobot (conf: Object): Robot if (! conf.laserColor) conf.laserColor = "red";  var robot: Robot = nieuwe robot (); for (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

Oke. Stel nu dat je merkt dat je bijna al je robots inschakelt om slecht te zijn (ik bedoel, waarom niet?), Dus het is eigenlijk best lastig om elke keer "kwaad" als parameter te schrijven. Natuurlijk wilt u 'kwaad' als standaard instellen, maar u niet doen wil een standaard materiaal instellen.

De enige manier waarop u dit kunt doen, met een normale set functieparameters, is om de volgorde van de persoonlijkheid en materiaal parameters:

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

Ah, maar nu moet je de volgorde van de argumenten omdraaien bij elke functieaanroep!

 generateRobot (2, "evil", "steel"); //werkt niet meer

Een configuratieobject geeft dit probleem niet. Bekijken:

 functie generateRobot (conf: Object): Robot if (! conf.laserColor) conf.laserColor = "red";  if (! conf.personality) conf.personality = "evil" // dit is allemaal hetzelfde generateRobot (arms: 2, material: "steel"); // nee "personality" -parameter? geen probleem!

Netjes! Al je oude generateRobot () functieaanroepen blijven werken, maar u kunt nieuwe oproepen maken waarvoor u niet hoeft te specificeren persoonlijkheid.

Je kunt zelfs besluiten om van de persoonlijkheid parameter helemaal:

 functie generateRobot (conf: Object): Robot if (! conf.laserColor) conf.laserColor = "red";  if (! conf.personality) conf.personality = "evil" var robot: Robot = nieuwe robot (); for (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; 

De bovenstaande versie van de functie verwijst niet naar conf.personality helemaal - maar u krijgt geen foutmelding als u nog steeds dergelijke oproepen heeft:

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

Natuurlijk kunt u een paar verwarde gebruikers krijgen als u dergelijke oproepen heeft:

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

... omdat alle robots nu slecht zijn. Maar de code zal tenminste compileren.

Om dezelfde reden kun je de volgorde van de argumenten veranderen zonder dat het er toe doet, en zelfs nieuwe parameters toevoegen die nog niets doen:

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

Het gemakkelijker maken om de standaardwaarden in te stellen

De code voor het instellen van de standaardwaarden is tot nu toe gemakkelijk te begrijpen, maar het zal erg vervelend zijn om uit te breiden als we veel parameters nodig hebben:

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

Laten we wat meer algemene code schrijven om hiermee om te gaan:

 var-standaardinstellingen: Object = laserColor: rood, personality: "evil" voor (var-sleutel: String in standaard) if (! conf [key]) conf [key] = defaults [key]; 

Dat voor loop kan een beetje verwarrend zijn, dus ik zal het opbreken. Bekijk eerst dit:

 for (var key: String in defaults) trace (key); 

Dit is een voor in loop, die de namen van de sleutels binnen de standaard voorwerp:

 laserColor persoonlijkheid

Bekijk vervolgens deze regel:

 trace (standaard [ "laserColor"]);

Dit wordt uitgevoerd rood - het is hetzelfde als schrijven trace (defaults.laserColor).

In navolging daarvan, bekijk dit voorbeeld:

 var voorbeeld: Object = demo: "test"; trace (bijvoorbeeld [ "manifestatie"]); trace (bijvoorbeeld [ "foo"]);

Wat denk je dat dit zal produceren?

Goed, Bijvoorbeeld [ "demo"] is hetzelfde als example.demo, wat gelijk is aan "test". Maar example.foo bestaat niet, dus bijvoorbeeld [ "foo"] zal terugkeren nul. Dit betekent dat !bijvoorbeeld [ "foo"] (let op het uitroepteken) is gelijk aan waar.

Zet dat allemaal samen, en je zou moeten kunnen begrijpen waarom deze code werkt:

 var-standaardinstellingen: Object = laserColor: rood, personality: "evil" voor (var-sleutel: String in standaard) if (! conf [key]) conf [key] = defaults [key]; 

Geef me een seintje in de comments als je een handje nodig hebt!

Ik wil meer!

Probeer dit voor een nog snellere versie:

 functie generateRobot (conf: Object = null): Robot var conf: Object = conf || ; var-standaardwaarden: Object = laserColor: rood, personality: "evil" voor (var-sleutel: String in standaard) conf [key] = conf [key] || defaults [key]; 

De verandering in regel 1 (en nieuwe regel 2) betekent dat zelfs de conf object zelf is optioneel, dus u kunt gewoon bellen generateRobot (). (Natuurlijk moet u de code wijzigen om te gaan met de waarden die momenteel geen standaardwaarden hebben.)


Helpen dat de IDE u helpt

Zoals ik hierboven al zei, kan de IDE u geen tips geven over welke parameters een functie verwacht, als die functie een configuratieobject gebruikt. Dit is een groot nadeel, want het kan uw code echt moeilijk maken om te gebruiken; je moet onthouden welke parameters er in gaan conf object, evenals al hun namen en typen.

Maar we kunnen deze informatie nog steeds weergeven aan de codeerder wanneer dat nodig is; we moeten dit gewoon handmatig doen, zoals:

 / ** * Genereer een robot op basis van de opgegeven parameters. * @ Param conf-configuratieobject. Verwacht: * arms (int) Aantal armsrobots zou moeten hebben. * personality (String) Persoonlijkheid van robot. Kan "slecht" of "goed" zijn. Standaard ingesteld op "kwaad". * materiaal (String) Waar moet de robot uit bestaan? Kan op dit moment "staal" of "hout" zijn. * LaserColor (String) Kleur van de laser van de robot. Standaard ingesteld op "rood". * voice (String) Vocal stylings of robot. Momenteel niet geïmplementeerd. * @return De voltooide robot. * / functie generateRobot (conf: Object): Robot //

Nu, als ik een oproep naar deze functie begin te schrijven in FlashDevelop (mijn IDE naar keuze), zie ik dit:

Natuurlijk, het is een beetje vervelend om dit handmatig bij te werken, maar in veel gevallen is het het waard.


Conclusie

Ik beweer niet dat je een configuratieobject moet gebruiken elke functie je creëert vanaf nu; zie het gewoon als een andere nuttige tool in je arsenaal.

Persoonlijk vind ik het een bijzonder nuttig patroon wanneer ik de eerste versie bouw van een aantal klassen die allemaal moeten samenwerken. De extra flexibiliteit van een conf geeft me zoveel meer flexibiliteit, dat ik me vrij maak om alle verschillende functies te doorzoeken en de manier waarop ze elkaar bellen te veranderen, zonder me zorgen te maken dat de code wordt overtreden door een parameter in te voegen of te verwijderen.

Denk aan de voordelen:

  • Het is eenvoudig om parameters toe te voegen en te verwijderen (aan elk uiteinde).
  • Het is eenvoudig om standaardwaarden in te stellen.
  • U hoeft zich geen zorgen te maken over de volgorde van de parameters.

Er zijn echter nadelen aan het gebruik van eenvoudige objecten zoals ik, vooral als je dit doet in een project dat voorbij de prototypingfase is. Bekijk de geweldige reacties hieronder voor meer details!