Vad är ett konfigurationsobjekt, och varför bry sig om att använda det?

Det är en smärta att man måste ändra parametrarna för en funktion; du måste ändra alla andra samtal till den funktionen för att undvika fel. Men du kan komma runt detta med bara en parameter: ett konfigurationsobjekt.


Vad det ser ut som

Här är ett dumt exempel på en funktion för att skapa en robot:

 funktion genereraRobot (armar: int, personlighet: String): Robot var robot: Robot = ny robot (); för (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 är det samma exemplet med ett konfigurationsobjekt:

 funktion generateRobot (conf: Object): Robot var robot: Robot = ny robot (); för (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");

Jag har markerat de linjer som behöver ändras. du kan se att det inte finns någon stor skillnad.


Varför bry sig?

Så om det inte finns någon skillnad, varför skulle vi bry oss göra det andra sättet? Det gör trots allt faktiskt lite svårare att använda; medan före vår IDE skulle kunna ge oss denna information om parametrarna som förväntas:

... nu kan det bara ge oss detta:

Antag att du vill lägga till ett par fler parametrar: en specificerar materialet att använda och en annan för att ange vilken färg dess laser ska vara. Det är inte för hårt, i båda fallen:

 funktion genereraRobot (armar: int, personlighet: String, material: String, laserColor: String): Robot var robot: Robot = ny robot (); för (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");
 funktion generateRobot (conf: Object): Robot var robot: Robot = ny robot (); för (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");

Hittills, fortfarande inte mycket av en skillnad. Vad händer om du vill att dina robotar till alla har röda lasrar som standard? Enkelt igen. Utan ett konfigurationsobjekt behöver du bara ändra metodens signatur ( fungera linje) och sedan kan du ta bort det senaste argumentet från funktionssamtalet:

 funktion genereraRobot (armar: int, personlighet: String, material: String, laserColor: String = "röd"): Robot // det här är detsamma generateRobot (2, true, "steel"); // Jag tog bort det sista argumentet

Med ett konfigurationsobjekt är det lite knepigare - men inte så mycket:

 funktion generateRobot (conf: Object): Robot if (! conf.laserColor) conf.laserColor = "red";  var robot: Robot = ny robot (); för (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

Okej. Antag nu att du fastställer nästan alla dina robotar för att vara onda (jag menar, varför inte?), Så det är faktiskt typ av smärta att skriva "ondska" som en parameter varje gång. Naturligtvis vill du ställa in "ondskan" som standard - men du inte vill ställa in ett standardmaterial.

Det enda sättet du kan göra med en vanlig uppsättning av funktionsparametrar är att byta ordning på personlighet och material parameters:

 funktion generateRobot (armar: int, material: String, personlighet: String = "evil", laserColor: String = "red"): Robot 

Åh, men nu måste du byta ordningsföljdens ordning på varje enskilt funktionssamtal!

 genereraRobot (2, "ondska", "stål"); // fungerar inte längre

Ett konfigurationsobjekt ger dig inte detta problem. Kolla in det:

 funktion generateRobot (conf: Object): Robot if (! conf.laserColor) conf.laserColor = "red";  om (! conf.personality) conf.personality = "evil" // det här är detsamma generateRobot (arms: 2, material: "steel"); // ingen "personlighet" parameter? inga problem!

Propert! Alla dina gamla generateRobot () Funktionssamtal fortsätter att fungera, men du kan skapa nya samtal som inte stör att specificera personlighet.

Du kan även bestämma dig för att bli av med personlighet parameter helt och hållet:

 funktion generateRobot (conf: Object): Robot if (! conf.laserColor) conf.laserColor = "red";  om (! conf.personality) conf.personality = "evil" var robot: Robot = ny robot (); för (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; 

Ovanstående version av funktionen hänvisar inte till conf.personality alls - men du kommer inte få ett fel om du fortfarande har samtal så här:

 genereraRobot (armar: 2, personlighet: "ondskan", material: "stål");

Visst kan du få några förvirrade användare om du har samtal så här:

 genereraRobot (armar: 2, personlighet: "bra", material: "stål");

... eftersom alla robotar är nu onda. Men åtminstone kommer koden att kompilera.

Av samma anledning kan du ändra ordningsföljden utan att det mattas alls och till och med lägga till nya parametrar som inte gör någonting än:

 genereraRobot (material: "stål", laserColor: "grönt", armar: 2, röst: "Mr. T");

Gör det enklare att ställa in standardvärden

Koden för inställning av standardinställningarna är lätt att förstå hittills men kommer att bli väldigt irriterande att utvidga om vi behöver ha många parametrar:

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

Låt oss skriva en mer generell kod för att klara det:

 var standard: Objekt = laserColor: röd, personlighet: "ondskan" för (var-tangent: String i standardvärden) if (! conf [key]) conf [key] = standardvärden [tangent]; 

Den där för Slingan kan vara lite förvirrande, så jag slår ner den. Först titta på detta:

 för (var-tangent: String i standardvärden) spår (tangent); 

Det här är en för ... in loop, som kommer att skriva ut namnen på nycklarna inuti standard objekt:

 laserColor personlighet

Titta nu på den här raden:

 trace (standard [ "laserColor"]);

Detta kommer att matas ut röd - det är detsamma som att skriva spåra (defaults.laserColor).

Sedan följer du det här exemplet:

 var exempel: Objekt = demo: "test"; trace (exempel [ "demo"]); trace (exempel [ "foo"]);

Vad tror du att detta kommer att ge ut?

Väl, exempel [ "demo"] är det samma som example.demo, vilket är lika med "testa". Men example.foo existerar inte, så exempel [ "foo"] kommer att återvända null. Detta innebär att !exempel [ "foo"] (notera utropstecken) motsvarar Sann.

Sätt det hela tillsammans, och du borde kunna förstå varför den här koden fungerar:

 var standard: Objekt = laserColor: röd, personlighet: "ondskan" för (var-tangent: String i standardvärden) if (! conf [key]) conf [key] = standardvärden [tangent]; 

Ge mig en rop i kommentarerna om du behöver en hand!

Jag vill ha mer!

För en ännu snabbare version, prova det här:

 funktion generateRobot (conf: Object = null): Robot var conf: Objekt = conf || ; var standard: Objekt = laserColor: röd, personlighet: "ondskan" för (var-tangent: String i standardvärden) conf [key] = conf [key] || defaults [nyckel]; 

Förändringen i Linje 1 (och Ny Linje 2) betyder att även conf objektet är valfritt, så du kan bara ringa generateRobot (). (Självklart måste du ändra koden för att hantera de värden som för närvarande inte har standardinställningar.)


Hjälp IDE hjälpa dig

Som jag nämnde ovan kan IDE inte ge dig några tips om vilka parametrar en funktion förväntar sig om den funktionen använder ett konfigurationsobjekt. Det här är en stor nackdel, eftersom det kan göra din kod verkligen svår att använda. du måste komma ihåg vilka parametrar som går in i conf objekt, liksom alla deras namn och typer.

Men vi kan fortfarande visa denna information till kodaren när det behövs. vi måste bara göra det manuellt, så här:

 / ** * Generera en robot, baserat på de angivna parametrarna. * @param conf Konfigurationsobjekt. Förväntar sig: * armar (int) Antal vapenrobotar ska ha. * personlighet (String) Personlighet av robot. Kan vara "ont" eller "bra". Standard till "ondskan". * Material (String) Vad roboten ska göras av. Kan vara "stål" eller "trä" vid denna tidpunkt. * LaserColor (String) Färg på robotens laser. Standard till "röd". * Voice (String) Vocal stylings av robot. För närvarande inte genomförd. * @return Den färdiga roboten. * / funktion generateRobot (conf: Object): Robot //

Om jag börjar skriva ett samtal till den här funktionen i FlashDevelop (mitt IDE val) ser jag detta:

Visst, det är lite ont att hålla det manuellt uppdaterat, men i många fall är det värt det.


Slutsats

Jag hävdar inte att du ska använda ett konfigurationsobjekt för varje enskild funktion du skapar från och med nu; Tänk bara på det som ett annat användbart verktyg i din arsenal.

Personligen tycker jag att det är ett särskilt användbart mönster när jag bygger det första utkastet till en uppsättning klasser som alla behöver arbeta tillsammans. Den extra flexibiliteten hos a conf ger mig så mycket mer flexibilitet, frigör mig till zip runt alla olika funktioner och ändrar hur de ringer varandra, utan att oroa dig för att bryta koden genom att infoga eller ta bort en parameter.

Kom ihåg fördelarna:

  • Det är enkelt att lägga till och ta bort parametrar (i båda ändar).
  • Det är enkelt att ställa in standardvärden.
  • Du behöver inte oroa dig för parametrarnas ordning.

Det finns nackdelar med att använda enkla objekt som jag har, dock - speciellt om du gör det i ett projekt som är förbi prototyperingsfasen. Kolla in de stora kommentarerna nedan för mer information!