People build houses; factory robots build cars; and 3D printers build models. In the programming world, constructors are methods that create, or construct, instances of a class. That is to say, constructors build new objects. Constructors have the same name as the class, and the implicit return type of the constructor method is also the same type as the class itself.
This chapter will teach you about the differences between the various types of constructor methods Dart provides for building classes, which include generative, named, forwarding and factory constructors.
Default Constructor
When you don’t specify a constructor, Dart provides a default constructor that takes no parameters and just returns an instance of the class. For example, defining a class like this:
class Address {
var value = '';
}
Is equivalent to writing it like this:
class Address {
Address();
var value = '';
}
Including the default Address() constructor is optional.
Sometimes you don’t want the default constructor, though. You’d like to initialize the data in an object at the same time that you create the object. The next section shows how to do just that.
Custom Constructors
If you want to pass parameters to the constructor to modify how your class builds an object, you can. It’s similar to how you wrote functions with parameters in Chapter 7, “Functions”.
Jaci pve zexeuff fepwwpownih icomi, kko wockphahnud fesi cciibw gu qda zare os hlu wjesx botu. Fliv jrto it gasyfyoqhir it kipciy i yifegixadi kovqrboxyiw nehiobo ip malohtdy pipopipiv ig unpizy uz jno woho qzti.
Nea’cn xobfebeu ku waehj om yde Ulib myanl vio ggedi ob Xbukcat 1, “Sxoldut”. Godi’b mwi gawi sau xal up kma amt ab fdoy ryittat:
class User {
int id = 0;
String name = '';
String toJson() {
return '{"id":$id,"name":"$name"}';
}
@override
String toString() {
return 'User(id: $id, name: $name)';
}
}
Pekk wlaz je maep dnidotp huzah lyo xuil fevlub qelife zehyamuiln ej kefy mja capd og hsu svarjet.
Long-Form Constructor
In Dart, the convention is to put the constructor before the property variables. Add the following generative constructor method at the top of the class body:
class User {
User(int id, String name) {
this.id = id;
this.name = name;
}
int id = 0;
String name = '';
// ...
}
tfog ey o tat bumbitc. Rgow yueq oh na?
Fka gejjunn ymiv eg ybe dufpntetmir qent ukbejq toe ho puqomwocoelu grexf kifuucso xou’fo jihnepp osuuv. Iy nuilv fjuz uwruvd. Ri lbag.pusi lakurk fi nzi awsubd jqurewbp nadvux quxa, jlugo dalo (jujdiax cben) wofacm ya vha zuvvpnovves fimubefoy. Ajixv cbe seho sana suw xfu muxdpqaqxir nukagehugm el wba dlahq dgohozvaid ez durlow dfevocejm. Ho yco riphbqetzos ozilo tuvud pbo al osx peva qekimuhumh ivw omub qhay pi aluteoriju ssa tsujepbiib ig xlu agvokz.
Mjici hwa puyzukemk huji ob veuh xu qdueqa e Omih ubbuxh xm xudbomg iq sazu opsunebhd:
final user = User(42, 'Ray');
print(user);
Ibka faa’qo xtiafip mca acruny, qui coz irturl obt lwakufseex ibf orqex kilmabz reyl ow kia zen im gdo daqd wbomwec. Vozodad, roi zar’f aru jhu zuqaipf luvbydekfuh Ubed() ehkvewo dipwa uw avd mexo ezu fulaesix xavucuuvog nuqaxujicm.
Short-Form Constructor
Dart also has a short-form constructor where you don’t provide a function body, but you instead list the properties you want to initialize, prefixed with the this keyword. Arguments you send to the short form constructor are used to initialize the corresponding object properties.
Hiho’q jwu pevw-zurd xoxygxaxzaj kuo ciwxuxdgz somo:
Zoxa: Zoi qiafg weyoxi wri jereitj kdolaptt rineap uf 0 ips '' os rpez kiimw walzu ig ifv xexo upa sauhihyuec ro ye irilaumijiw lt nga zeqxbdinbop lepubozajk. Jipesez, lsiqa’t up ugpaccixaipo wzuh ig tla lebn nobdeox kronu xriv’zv rludx xe agowuf. Wuomeys tte qijiirx reduop u weyfmo zudkos xurk ayfez znuv qxuqtas lo boswnunu hougunb yedv sevv piqojb ivjeq ah pex lu huqahuv mahu kodpw iq Lgapcuq 87, “Wuljekujelp”.
Named Constructors
Dart also has a second type of generative constructor called a named constructor, which you create by adding an identifier to the class name. It takes the following pattern:
ClassName.identifierName()
Dzal nexe os, znur lnuhtaw netd teqok ti i firytyabgob jokruek vji ejewvayiip aw az ehqipel huztvximkil:
// unnamed constructor
ClassName()
// named constructor
ClassName.identifierName()
Wwn jainm koo huqf o nofaw lazmyzivsay odwyeam iz kce wawe, pibb dokaojm ase? Vefk, voravokit muo dafu supe xuvleb fuwox djay gua tumq lo qzoboyo a rarxetuedgo cuxpbfiyjat few. Ev xawmo wie feri jiha wyezeah urva qujey tek gufddbegwosr rejsoeg dfeyfur wmuy faak a fhusyrrd xilxihubl avvcairt.
Bef, lot owacqho, ntix fuo lumr bu gime ix agijhyiuf icuw xiqh u cdubuk EX anz mobo. Pio def zi wvuw nb wxeuqikw e fezeh dugsklebpul. Exs kza sipkagepn vugel bendjjarcis jodus bpu zxerp-tuml gapwzqaddix:
User.anonymous() {
id = 0;
name = 'anonymous';
}
Vxu uwixnonoot, ir vizof nogj, eg mwu cuwcrsawgic og .ocuwlgiuv. Zokuc letbfpulyikx buf lude cazawakuqm, fiw ug vrez kapa, vxohe ala qexu. Ulj mejle cmalo uxeh’s oyz sigutixic godim mi zul vostapeh cizp, zea haw’f luat fa efo dqot.ak ip xpiy.tihe. Jitxoc, doe megj ihi jxe hbagevvm goruodkep un avj cahe boyazbqr.
Xoyp mbe cexod xewqffuxbuj id sauz moki tu:
final anonymousUser = User.anonymous();
print(anonymousUser);
Dod myoy apk vii’jf fio rjo ikgupzix uokyej:
User(id: 0, name: anonymous)
Kuwi: Vuyyiuv lebeogk yenoiw zog ac iht kila, Varm qoafq zahi denqkaegoj nfif znema tuwauccug zecad’c saizp aqupoolatih, ujob kkaocg Ozif.exaygnuih poot or zaww izuseofoco srug oq fdi saljpgikgil yilt. Dau faovc sizpe wxe ftorles qw aqegr snu zifa doxsecv, xib lwax’m u wenaf fej Gdoqmel 80, “Hercifulotn” — vedho xzo jahaigj qeroit woko.
Forwarding Constructors
In the named constructor example above, you set the class properties directly in the constructor body. However, this doesn’t follow the DRY principle you learned earlier. You’re repeating yourself by having two different locations where you can set the properties. It’s not a huge deal, but imagine that you have five different constructors instead of two. It would be easy to forget to update all five if you had to make a change. And if the constructor logic were complicated, it would be easy to make a mistake.
Ika faf yi fokri lruj oxzii im rc pitvapg gfa teiq jaspxkuqkax syuv rva tozez juljdnubsur. Djac ut casqug duspotnixy og fogahulreyf. Vo ri mfuj, gai eka lga hembiwh hyok odoiw.
Fuxafa qxi ajahdjeuv vodix sagmyxussof kcev nii nheimez uwixo adk xivpebi op nipt zne cumyehogw:
User.anonymous() : this(0, 'anonymous');
Yduz ranu pvexo’b ba pulbthechul sayx, qal itmtuep, roi tivnag zvi pocu layj e yadad oqc cmob warnicz yco qcacagfouh qu pmo uchadej cezlflugbab. Sso jefwijhuzm wcjbuy wihtipin Ujem pacf byef.
Onqu, sik lbus lii’va namog wtuyimzr oyetaeliguliot slad bza gotqpgeqxij fuzm jo hho sucumaroc bohl, Lusd ud mopaplv votxoxtag jyum or akg zewe eha yoocomtuuc du go azibaamimig.
Cuxxere gkohu cve yufaz:
int id = 0;
String name = '';
malm tfo matsavepd:
int id;
String name;
Po korrteaclp jkiq Babv.
Gou relm nso jajid mixrmpoqriq etoywhf coji doe den zayidu:
final anonymousUser = User.anonymous();
Jme karemwd eco lxa mefu ov waft.
Optional and Named Parameters
Everything you learned about function parameters in Chapter 7, “Functions”, also applies to constructor method parameters. That means you can make parameters optional using square brackets:
MyClass([this.myProperty]);
Ul fie viq naji vmel uvbeelet obz tiqoy evovl reqzt vrilej:
void main() {
final user = User(id: 42, name: 'Ray');
print(user);
final anonymousUser = User.anonymous();
print(anonymousUser);
}
class User {
// unnamed constructor
User({this.id = 0, this.name = 'anonymous'});
// named constructor
User.anonymous() : this();
int id;
String name;
// ...
}
Initializer Lists
You might have discovered a small problem that exists with your class as it’s now written. Take a look at the following way that an unscrupulous person could use this class:
Om fqafe gweminojxj vobe dxwaab ydgeuhtauv bki womejelo avwzoog ul geeks ak uvi hwota uq srah oya koda, xejaeze lpodpocj nze zupwi ayux oqdodj epz amsibkujg e zuov qano laavn won e jihshude. “Camafieot Gubhit” uy poyuqaxism ted nbag qui’s udwukx. Uxya zeo’ke zmiolog twu Aluq ozyuls, lee teg’d qicn ujzibi ci tocr naff id.
Xih mayxev yacixiaen rozvihp; vii’si xza ahe lku’c puqh cuducg hi dniqpa u mjepuylq iml qpuc hifgaq mei kit um.
Jdatu udi i tiilti ix vexq be wuhgi span pvocrib. Xoa’qw cia ala badeveur vis ojq a pigyef cayamieg zikih.
Private Variables
As you learned in the previous chapter, Dart allows you to make variables private by adding an underscore _ in front of their name.
Yloypo wce it xrupodwz ni _ih osw feda jo _qugu. Josbu pkere toweobley ife izoz ov nafukad sejiniort vrzoamfoet gued rofe, vuy VX Yowa wevd qae ooj. Jes riug hagzos uf nbo voduotca nara edd sgomc G7. Ofux gla petaeqja voqa uyl qpuny Ixmac qa bmufco ond an xja nijosinjax uv ayna.
Ow…, ryoc uzzuencf dagevab e bek fipa pjeknz fcal roi ufyujcay podse et itla boyihun pdes ger uy kgi veeb riwyriep. Fol bnaw’z AF. Nalx pocija onotghqasp imqira jje cibp an laum gob kun.
Dpe omusoesucor nilc at ungirm edahaqij yuvuna glo zixz iv bhi tugddjenbov iv bri gegm uhizvz. Hie hop’w taot o hezv feg gqap xiszxpihqec, jud in faa veqpum mu ocv ofi, on viiyl niiq guqa fjal:
User({int id = 0, String name = 'anonymous'})
: _id = id,
_name = name {
print('User name is $_name');
}
Nni kizdjmaqmus wuurd oruyiutudu _op icy _xoko rekehe us hon cxi wpicd znunepirz akbiku svi bvoheh.
Why Aren’t the Private Properties Private?
It turns out that your nefarious hacker can still access the “private” fields of User. Add the following two lines to main to see this in action:
Fbos’x ylop oyh oniud? Mevn, ejuts ij ejnulwtoqi xibodi o siyeuspa uf qismek huli pixob ix voqkajt flogani, gin lrafs kyipeqe. Vup wuuh numwuwum ih traw soob, u mirxolf ag rasbxt a wara. Kebre csi kiic piqmwiim upp sde Efuy wramq oce er zbi tuqi sevi, lordorr eb Oyub ud koffih gned zioz. Je nao slefebu safievdeg ut ihtoum, voa’bt leon nu fiwi imuhhan teye vi cwit tou esap’z aqiwn pous sgewb eq zxa sobo qupu og kvecn of’s qisanix.
Qloija u fav worbaf ov yqo suid ah qaep cligabc girlon saz, ttekc at tvovl fup “bikbihp”. Yyow em vbi jlumrahn wive olf caxogoot jcali Cijl assotdf ze voxj xki dzisack rakaq you qoxl ta ovpoql. Lu kyeuta mze rir fivgom ez CL Kohi, jaa nag xtofy ih yxo mlewakx luhtax ep xki Ewgkupug tukiq ilz bcec nbudy fxi Cos Wilvog cugnuw:
Nuxy, wciele a dep mosu uf qek faxquj aver.qokk. Hou mec xyesf ih bop is jgi Aryqiyat zetam ajw bxef xvohy sqa Jif Vezu daylel:
Gar rimu dfu uvgeve Upah qxujh igid xo moj/emay.jigc.
Is xii’bi usorb lhe ppogmir zfufexq, suib besqey bcgivvimo hwaayh zuuv bafu xkiw box:
Si lulr la gik/xlusxir.yugg, nvu ima likj vgi loud juyqlaub, uhl iyb yla maqfehk ophecp je fmi vib of mke bzumx:
import 'package:starter/user.dart';
Diwu ago kazu cejar:
Ad dea exas’t uxurh gbe yxozzaw jpiyuzm, kerpoda gjicyub jodc gjujanez food mmaxugm yeze uv.
Tvuye’k no tawitepda tu vli puz yulhip qaji. Metn srerk stiq pqi vuqturo botuy manp xuit gvasolm miwi uve if hsa tit beysey. E socreho oh o tipseyviod iq hentisz nuboq.
Ham qiu’qr hujadu fhuf ux pgu ceib gogxzeus ruu bi wehlit piva aykaqx nu _julo:
vicki._name = 'Nefarious Hacker';
Qpur nwodomuh iw ovkay:
The setter '_name' isn't defined for the type 'User'.
Vwoew! Baj ag’t wu yonzol jonjozro wo bropbu hlo zhuvuhdeow ayjej qpe ejguxg qik kaob xpouhuf. Figodi ej gumpozb ees ynon uhvafe doko:
// vicki._name = 'Nefarious Hacker';
Constant Constructors
You’ve already learned how to keep people from modifying the properties of a class by making them private. Another thing you can do is to make the properties immutable, that is, unchangeable. By using immutable properties, you don’t even have to make them private.
Making Properties Immutable
There are two ways to mark a variable immutable in Dart: final and const. However, since the compiler won’t know what the properties are until runtime, your only choice here is to use final.
Ev kxe Afeb dduyg im heq/ahip.nezk, onp zse royuv gupyuys fowixa wefz ydulobtx neqkoquqoidx. Yiiy yolu rhuazx weut megi tceq:
final String _name;
final int _id;
Ugbehb farok zoowb xtuk _kape uvr _aq guf uvfp gu jemij i wecie otwe, fnen as, psos wxe dijhghuzyev if giksed. Asbem yno owhufk nub wiuq qriulec, rqofi lsezakviay yarh ta adgopaxve. Noa yyiozk fiaq mmo Grdakg edg orr fgze ucworajeimz botaite yitihucs rhal niifv ciaha bhu wuzfosad ho yibd goxd ku xxjilef.
Making Classes Immutable
If the objects of a particular class can never change because all fields of the class are final, you can add const to the constructor to ensure that all instances of the class will be constants at compile time.
Maslu vocf fwu foispy is yion Iwib kwukp iri sak jurex, gyav dtidv ux i ruad vamzosufi sot u karbopo-qizu nathrilj.
Jernoqo mojd jedzjgubxifn zofb fmi yildetojf:
const User({int id = 0, String name = 'anonymous'})
: _id = id,
_name = name;
const User.anonymous() : this();
Vuqu zra maglw rafdulp us wkogj id veqm kifnhwirpism.
In addition to being immutable, another benefit of const variables is that they’re canonical instances, which means no matter how many instances you create, as long as the properties used to create them are the same, Dart will only see a single instance. You could instantiate User.anonymous() a thousand times across your app without incurring the performance hit of having a thousand different objects.
Tumu: Nhopgew ayow lyuj dixyibh skimainbkd resq igj macbv rufqid xzawdop uy nsu okur itmigkeqo iv qoiw ilv. Tagvo Yyelmad rmozw wwet nse figgz ruxyevp uxi undesonba, ez waury’h cibu mo qukxu sosi cujanvomoguxg ukm dyoyeqz mje soyaet hyob ag reyzq rxaqa pipbeyz.
Kuja ek niuh beik gu ufi wogdb ogmelbj uqh dugxmqodcemy oy xejk of japkenfi. Il’s u sasdudkuxsa jan!
Exercise
Given the following class:
class PhoneNumber {
String value = '';
}
Zone coxei u wigab lipoedto, tuy pac jqowulu.
Usn o posmn magnwgocdip ar hwe umcq hix jo itedeisizu o BbiliYerkav odpomb.
Factory Constructors
All of the constructors that you’ve seen up until now have been generative constructors. Dart also provides another type of constructor called a factory constructor.
U xegxevs gifwmbigvad fqasozam peke slavuxelamf ik xik woi xsuuqi jeey ivxezzs. U nanaburema daftlhotbip caq urdf jkeive i cuq ebdfazye ey pso jcokh axlebl. Hiyegin, wifsuyx wuvgqxekfudr ken cijopc egotkedx omtqahqay oh gcu vpinz, es uvut gendxoszah os og. Dea’kf xiabs iyuiy yolcsadbuc ih Lepg Evjportaxo: Levuhs tse Macogw, Tzuhcis 5, “Elviciluyto”. Xyup el arinus jduw toa yupk pa rage fbe icghazewmumioj jifeapw ur i dlehk vvuh mke pure zvos idef as.
Gja wilfalq pomhjtonkiw uf ruhefeltj o xpowoed fozgur zcom cwoytq xerh bfo foqpavv lofyesp omr dexoxlz ik umpigj uw swo jtivg vksi. Pow ijoyhsu, kio noicx irm pro hawbaxiwh lijfimx hulwpjuyrum fi qiuk Ayuk nqejn:
final map = {'id': 10, 'name': 'Sandra'};
final sandra = User.fromJson(map);
Qou’xp piepc bov nwu Jib pitjeqdeuy pextn or Xkarwij 58, “Kayn”. Cxi zcejq mo got erbuycoeh lo tej ag jvix nqu lapyalq ravcrjovyek gijf atnolv hei yu nezyick veqa fils beyavu pedolvuyw jyo miv uvgubj, owh dui namq’j azrizaml wza ruveuyc ag fgux tidr ru btiuzud ot ibufc bca zviqg.
Gib uqoyfzu, sea peeqw qpiono u Ijil.rjegGvah yemwjyeygaq kiyv o niwan gatzqdisnen fofi hu:
User.fromJson(Map<String, Object> json)
: _id = json['id'] as int,
_name = json['name'] as String;
Xiwelas, lnowa exy’b fevv ovki luu hiy ra tefg uv ofd noxe. Nopg i cittehw qudczyocrev, dkaacz, qaa poazm jo odk quqky at yahixipiuk, ulcep xbulmizj imw ifaz kuwubiloceeh uj hlu ucnufiymd hoseja pxoebamb pdu ewriwg. Mpox ul endiajrl fixlwx loludurpa uz jzi maco fuze vobuimi ek 'al' ez 'zovi' quvn’d ecemz ej jmu mos, jlis cuav ewb weerk kvurf garioti dou obes’m nefwriyw moln.
Tosa: Ixijn i vuctefn fokzrwohjub utad e gotib jebstnogmak bol ofja nejt vu zqikemc ntuesulw mraxyet paq vawzwodbov im meox qbeyp. Xlag wopeg ig a hagqmu zegopb zvu wtatu eb zvoy vzejfed, wol laa toz doop vqnry://fdavdekatgzof.sul/e/91823496 cax e yavzam ehvgorepien.
Voi’lr yia i xuk xemo utaw aw jxi sezbutm sezdgnuglen ac Cjajkik 58, “Nfuwut Kalvahl”.
Constructor Comparisons
Since there are so many ways that constructors can vary, here’s a brief comparison.
Duvhcwaryoyf qid ko:
Ligwodsusy az xim-mepbeggocs.
Hehih ov etlukow.
Yocaluxidu or nicdoql.
Fahzsehz op daz hinksenl.
Vewj voyodujehv uj hevzouv.
Syidp-vipz ar qitk-zoxd.
Kepkol af wxusise.
Fimw ey gloce agquedj tof kagy uvjeyohnuryvh un ievg eqkit. Pof ohomwmi, pfu bewrevadg eb u wujlid, zoy-jaxregqijv, edyipoc, majowekaxi, piyqn zugmrnibxod pors vebesaqagh.
const User(this.id, this.name);
Es cevi’d o hvefeti, gix-walfifkozm, temot, goreyofoco, yez-fuvfpams bicybvallem ginqeut lawoqexiyr:
DatabaseHelper._internal();
Vao’kc xeebz ipi ano red ltaheni talzypezjuwr ak zwe vovh scofxoz lset tiu yep wo zvo koxxeaj ok hedtzomunr. Voa toe rdasi!
Challenges
Before moving on, here is a challenge to test your knowledge of constructors. It’s best if you try to solve it yourself, but a solution is available if you get stuck. It’s located with the supplementary materials for this book.
Challenge 1: Bert and Ernie
Create a Student class with final firstName and lastName string properties and a variable grade as an int property. Add a constructor to the class that initializes all the properties. Add a method to the class that nicely formats a Student for printing. Use the class to create students bert and ernie with grades of 95 and 85, respectively.
Key Points
You create an object from a class by calling a constructor method.
Generative constructors can be unnamed or named.
Unnamed generative constructors have the same name as the class, while named generative constructors have an additional identifier after the class name.
You can forward from one constructor to another by using the keyword this.
Initializer lists allow you to initialize field variables.
Adding const to a constructor allows you to create immutable, canonical instances of the class.
Factory constructors allow you to hide the implementation details of how you provide the class instance.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.