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.
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.
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");
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!
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.)
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.
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:
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!