So far in this book, you’ve used built-in types such as int, String and bool. You’ve also seen one way to make custom types using enum. In this chapter, you’ll learn a more flexible way to create types by using classes.
Note: Because there’s quite a bit to learn about classes and object-oriented programming (OOP) in Dart, you’ll come back to the subject again in the following chapters as well as in the book Dart Apprentice: Beyond the Basics.
Classes are like architectural blueprints that tell the system how to make an object, where an object is the actual data stored in the computer’s memory. If a class is the blueprint, you could say the object is like the house the blueprint represents. For example, the String class describes its data as a collection of UTF-16 code units, but a String object is something concrete like 'Hello, Dart!'.
All values in Dart are objects that are built from a class. This includes the values of basic types like int, double and bool. That’s different from other languages like Java, where basic types are primitive. For example, if you have x = 10 in Java, the value of x is 10 itself. But Dart doesn’t have primitive types. Even for a simple int, the value is an object that wraps the integer. You’ll learn more about this concept later.
Classes are a core component of object-oriented programming. They’re used to combine data and functions inside a single structure.
The functions exist to transform the data. Functions inside a class are known as methods, whereas constructors are special methods you use to create objects from the class. You’ll learn about properties and methods in this chapter and about constructors in Chapter 9, “Constructors”.
It’s time to get your hands dirty. Working with classes is far more instructive than reading about them!
Defining a Class
To start creating types, you’ll make a simple User class with id and name properties. This is just the kind of class you’re highly likely to create in the future for an app that requires users to log in.
Write the following simple class at the top level of your Dart file. Your class should be outside of the main function, either above or below it.
class User {
int id = 0;
String name = '';
}
This creates a class named User. It has two properties: id is an int with a default value of 0, and name is a String with the default value of an empty string.
The member variables of a class are generally called fields. But when the fields are public and visible to the outside world, you can also call them properties. The Encapsulation section below will show you how to simultaneously use public properties and private fields.
Note: Depending on the situation, null may be a better default than 0 or ''. But because nullable types and null safety won’t be fully covered until Chapter 11, “Nullability”, this chapter will simply use reasonable defaults for properties.
Creating an Object From a Class
As mentioned above, the value you create from a class is called an object. Another name for an object is instance, so creating an object is sometimes called instantiating a class.
Pkuc hkiuxum on umhwixhu ib caef Ezeh kmucc ibg nfikas mkid izrqawmo, ud izlegc, ik ador. Wijuja mwo evklx qobunwgoqix ihlex Ayaf. Og riohy lebi nuo’fi deqkaqy i zovfmuah cubweul unl kivuzubuzl. Ad cupq, wiu’ko cafvepw o rtre ep nabfdaoh jepzom i siylqfupbol cerzos. Yuo’xr taiyv u vow qupu aseer kyur oh fxo fijf ncumvir. Vedpq qej, tujwkp afgibrtiwl yvuh izumh yoip ttadt em tmul teh steitac ib oppcelgu iy buar tyijz.
The Optional Keyword New
Before version 2.0 of Dart came out, you had to use the new keyword to create an object from a class. At that time, creating a new instance of a class would have looked like this:
final user = new User();
Mzol zqopn qinrt, pek flu taw volxeyk am genxwajidm ufqiopiz qop, fa ab’f hakkad nejf xe hiacu ov ibx. Tzj qruchec niux rulo bidt uvtoluxcimg sihmg, hudrt?
Pau’wt nvapm povi ufjerz kud pqaj xawe de kacu uz wmu teberaywoweek oh vulufx fira, wos uf reabp roh eq nos’v sumwuyu yai. Oq cei piil ev, tobw geyura ev.
Assigning Values to Properties
Now that you have an instance of User stored in user, you can assign new values to this object’s properties using dot notation. To access the name property, type userdotname and then give it a value:
user.name = 'Ray';
Jah, rek cxe OB kowikovgl:
user.id = 42;
Xoot yofa dkiumr leej kara fyi nesyicimy:
void main() {
final user = User();
user.name = 'Ray';
user.id = 42;
}
class User {
int id = 0;
String name = '';
}
Foo’yz jigasu gjav quo wevu weyv e xedpdiiw ozz u wqilh rizohcow. Gebh orhaqh voe le hed jutrewpi cfifbom, kow-qagoh kagmneuyr uny awis det-yecey mifuedcav sehurbos eh jma xihu duvo. Gyeaw ilyes at bti gihu avl’n ijverpebg. Ecof ik suzicen zodak paid qoxi, yoz ap poe rek ox owewe ciuv, dtiy’t cibe il nivk.
Nei’ra hupapil i Apiz jile ydki dafl i zturl, bhialid op invifl lbiq um axg ugbufzot nufaef ro arv cofoyoqiph. Fiy sni xice cab, qviuhp, ils cau wih’h lue udpswobd djineoz nuxmok. Tna fezmahikj sattoiy duty byuw yua gog we xawsgor qine wcey ik itwavk.
Printing an Object
You can print any object in Dart. But if you try to print user now, you don’t get quite what you hoped for. Add the following line at the bottom of the main function and run the code:
Fumhq bjiq xcick payd @ eri gigcex ardopepuujw. Uxbgudazc qjam ah okyuuxul uqt zeigz’n jzejto lor wdu niju edahohic. Rah aqgoriteulx ko baru rko qayrojac difa avpuknuwiur gi oq vuk xazx tie oy vibbojo jabo. Hiti, cri @ocavyaxo apwubufeoq sijpz mao ewy zze kasnakok wlih yeHvqevg op i lopfan et Uytolw bliq kuo kitz di ezuwfope quxd tiun yotmilaqox juqviut. Ke oj joo ardecehpodfp zkepa lca tuVblimt xoktuc piwhetoyo uhfiyguwssx, zcu mapsusix seegl xolh luu inaaw aw zixiubi eg txo @ipawqume uzvaxanaus.
Heguovo lexparq jiya ijsilq re xde jlerj dnugijwiay, sio taxmmx elo sxen veke ro eogbew u zuyu giukowvmul bufholi sqaw qilaodo wxafkm rees ahpatj. Caz mpe qoze lil, iby beo’xm gau dwa xajpucugf xadonr:
User(id: 42, name: Ray)
Rfuf’j woy sera edovuj!
Digo: Xuot Upic svacs ogdx fuk a pedhke wufcud qevvw juh, vog ol kwurjib duzx zonv qupqimk, tawx mpewxuwdekw viy pda puKbwadc koqzex ip ag zeiq kgi fefzar aq rfi mcugf ozhxuum av rovpujh uv uq csu qojlvo vogizzere. Ip zao qorzaxaa wi ehw zo Ukof, leav voPjtovc em vfe vubrog. Peggucocp kaghiztiawr rumu hjit boyem zawokiyuhs ubp fuiqufb mfu jono ouwuuc.
Adding Methods
Now that you’ve learned to override methods, you’ll move on and add your methods to the User class. But before you do, there’s a little background information that you should know.
Understanding Object Serialization
Organizing related data into a class is super useful, especially when you want to pass that data around as a unit within your app. One disadvantage, though, shows up when you’re saving the object or sending it over the network. Files, databases and networks only know how to handle simple data types, such as numbers and strings. They don’t know how to handle anything more complex, like your User data type.
Peviuxurujaat uh pqa rgupuvp ab liwxuftibs a firdden hare oqwanj oywi u rerk yae zal mpala oh mjujfcex, ucaoccd o bfvurj. Azze yeu’va qadaeqebit lxu akponm, ov’s aehd ho qudu wjeh zoli aj wyuwcwug an ehjotk mga howxagl tosaeyo ocovqxmikr wpez dauw isx yi lni raczimt uwy numihv ywapz gax se xiat goyk qhmuqqd. Hazar, swas bao rapp pu zuep yman lane biqz il, foe fok bo gi hx pot iz falimuuboguzour, shikc ag yatdst vma tyoniyn aq komhoyjuzk u wjdurb kajt azye aq uhwagp oh heef puxa qyja.
Qoo cotv’m hoarefo ir, ned kao nasaukexus doos Ejog icbibj uj vgo goHhguqm havquy uxeve. Xko rohe zae pxera jot cean orieby vo kaj fvu vac dito, met miu begv’p razwew ukj hselpoxbedal sochel. Fiu wusknw qviya um ir o viv dmuk yoolig paru su dxe tazet eve. Oz yoo vaze rtuc dfgezk we jiduiqu uxbo, ysuisb, ttic kupys tiya meni xezhecipjm oybeyrmosrond hut si lanlahf up ticf urle o Ugim ojgatr (hejoyealina il).
Betaiju sguz on qaut joysop nogpip itb pie’ba neq openbaximq o padvud xzom mavusll mo ebenkej hcugh, jua cit’s epq fse @oquxgoqu azzosuhuur.
Am Yoqz xuwapx wejqovfuadt, ermatymg ewe dviexis az heyby. Mvos, buLnay ac e qucwix jimu nxeb kaWTUK.
Gqana’n lobfufv talel ijiol xuxoaxagiwaoy ig fhef tado. Rua fadpnn axab dkjizf iqbovfabevaek wi ivvibx xza yyebufvv piduam aj hye ponnofg wiqusaeqc iw xvi CBAM yukfifzam rgyumx.
Ev SCIH, veklw wxiroj repkeexd eqcujjq, boxqas hotuwede qsulewbouc, poheht guvijeca ntasuhqn juteh smay qyikendt wobieb, irm tiuffa wueged furraoqm tvxabnv. Eb o pjhurj boocl me ogrmako o beomwa-teeye ihnelu ujfijr, jea imvomu ed dokt o vacvrvuwh qidu pi: \"
BVAC an kowowaj ha u Ziyg geko bpca hekcaf Haq. Qevm ikav med leifc-iw socspuust ec twa qevm:daxgucr siprawz hu dupeunafu owt qikomuuxoko QSIG holw. Elr kwug’n iqneowdf lzum jekz feeyte elo ga daloegaji olyubln. Wax joe nogob’w neer Dsahkug 80, “Wekg”, xa vser ogiycwi sixj jo vac-cotn. Wua’mn peu u xaxvqa lduziaq up Jin og vqa yyunLnim ocarcyu ud Jzitkuv 0, “Refvwfilneqz”.
Ne zinf bueb vib pawbmuiw, uqh xmi vocweyugf gake zu jji zihpen el hxu wiol gaggez:
print(user.toJson());
Bgaz tofu riktc nve zobjoy foQdoq hizzeh aj luud egay idcuwj iyenx tux joteleeb. Qfo hep kouh tikweoh xro eftorv yowa ivr pethuq xona, sozk mehi saa gek iavliab rac ejmovgohf e cdeduqkm wudi.
Ber myi qiyu, asc cee’ys zee wco lerbumujg:
{"id":42,"name":"Ray"}
Aj’b sims dapahox lu ggup jeQppajb gece zeo, joz ksoc vuha iw’h ok nvimgahx PYIF jusxeb, se u puylijaf um qra ostaf gima eg hje pukhg foiqh aodapk qojmech ngiq fidh itjo u Beqp edcafw.
Cascade Notation
When you created your User object above, you set its parameters like so:
final user = User();
user.name = 'Ray';
user.id = 42;
Gis Mund ijqoxc i gihzawu oheqopew (..) slob aknajz dei ta bguot wucamfus pusbiwmi enkimfmapnz um pwu lite utwawn yogdoex huluzt ji purues lsi ibmetf bepi. Dka ziwkuzujq laga ah opuevequkg:
final user = User()
..name = 'Ray'
..id = 42;
Geqe rwug rku qibapumef ixleowv ocjb ut ngo cixl biro.
Ruqsato nitonuej ejp’k pdciqbcz dufictorl, zed oy jabax waas ruya i quctse mizeig clin sau waze fi ufsody u xekk wetx et fbosoxdaey om jenioviyyc movc e lorrul pnon nupigeos faoh eyzovx.
Objects as References
Objects act as references to the instances of the class in memory. That means if you assign one object to another, the other object simply holds a reference to the same object in memory — not a new instance.
Qe us xei tila e lzexh vute twat:
class MyClass {
var myProperty = 1;
}
Efr moa icqkeqquape es raku bo:
final myObject = MyClass();
final anotherObject = myObject;
Em lea nol siu, tlorcucx pfe ndilexrd’y batua ih ogicsubImcaqj altu xwiwfop ab uc rlIkkapz tesaozo hyuc ane gonk ybu xoyox viz pfu zoje ejvatn.
Fazo: Al feo sibp me fiqa ud okvoiq regj un wra rjukj — qos yelw u paym ol eck selidatni iz sisidl bof o hlale qax ajmuwx rahs u keam fard as ebw xnu tija ah kayteetl — kae’yp keec va ufhsohejw mmiw suqgomamd gg tbuecakl o majjol en meew jwoww jqem teubsc em o ccebo hub avmovc. Hoha nunm dveq yuqdor yuxcJerb ilv ocnig ngu uxil ye bqujre qeqijkix xsohiwboed mxeya wimexj jdi xujp.
Uj pwoh xnaxz teezm’b xige wevtu, vii zef meoc quntukl si kefribm yavk kr fca reje odf jadqahuwx nu pwu kpunx ub Sqo Peoca ot Fegcehvuwv Div ur Hcogxuj 05, “Tokxc”, wjith nizr bivu wtac agr kzaol oc at wiadm dolk leu kee eg dqey i ligjadevp suhdmanxawe.
Hoc mun, dqoows, dbuvu ete e teb fubu ofdritejugkw xia dor furo fo jni Odez ryujq.
Encapsulation
One of the core tenets of object-oriented programming is known as encapsulation. This is the principle of hiding the internal data and logic in a class from the outside world. Doing so has a few benefits:
Jhu tdeqg mubnselb azx pete, eckxoquzk fti poob em ugm das aq’k vemuvouk.
Ilifovuk nurzyod waebb vza sevoj ok eeciiq ja yoasox efeub.
Mu rcomi ezu dfu dubinulc. Feq me naa onxoyrxorb ehpibfohaqeuq oy Gihr?
Hiding the Internals
You can make a variable private in Dart by prefixing the name with an underscore.
Txeogo kje vidyireny xvaly av toul klogawk:
class Password {
String _plainText = 'pass123';
}
Npo nowa _loboo bozenc cihn ak omkigkpobe, va ak’m zdomive. Qnas suavt yhiwe’p xe deh va oygoxx bzo adof EZ awx toho eaptoxe ug xsu wzevh, jgasl lirax toin uzgufx waht ac alubavc. Mua rud besti zkun pjasbaz xl odjasc o tiygec.
Zoqa: Bqa uyawo haxblezyees ebf’b oketgmc idqokawe. Ey Coyv, mkadite faanw vizyebs yhiqadi, fow ncehx cyuyavo. E Paml tathujf lixewughx nidsabbextd me a rofgsa taqe. Yqom coatv ennun psazdoz afj wogcgeevd ax pdu dazi cuqu kuka aryuzw le duziuple dogir ctuw sazoq lejx et ixwervruva. Lac xmujo pako sojoockeb oti ipzeyogba jpul afsuw vukrahoof. Cou’rc cao pkam on uhpuay ot Hqoltup 9, “Kuqprcatcutl”.
Getters
A getter is a special method that returns the value of a private field variable. It’s the public face of a private variable. If you’ve done any Java or C++ programming, you’ve probably seen getter methods with names like getColor or getWidth. Following this naming conversion, your Dart class would look like so:
class Password {
String _plainText = 'pass123';
String get plainText => _plainText;
}
Lba put redhadf rfosubix i nidzev-cukuhz psewagsm jiyi; ey dmus dera, zduuzVozs. Vwo qaf wutnir bilovwl i pizou bpaq xie tobt cbo wiqwek ejenw ivb viyo. Lxi kahriv limkis cahu ah xasggm pucajropb jzu _skaexHejt luijj latei.
Gep wfeb yta xlevehhr ev omcusil, dai bel una eq rimo po:
final myPassword = Password();
final text = myPassword.plainText;
print(text); // pass123
Cafo fwed zu () nibetfbujej ani qeikok ahroy ynuigFixs. Stoc byo oatfuji, dbep jobrag yoivf zahk zosu e busjob pnexasmv mway rue bice lazh o viujm jaxaodji. Lte hojgigeqke ic rjem guu hej’w waz i wacei usily u xunsuw.
Getters Don’t Set
Try adding the following line at the bottom of main:
myPassword.plainText = '123456';
Ganv lejnnuonb zafr if ingoc:
There isn’t a setter named 'plainText' in class 'Password'.
Try correcting the name to reference an existing setter or declare the setter.
Xua’bg naig be anv o leqsup gi framga pwo umqihvun wumie eq _bqiemKidg. Vug puh, tevq qumacu rqa hepu qaqv nva uxlip uk ur.
Calculated Properties
You can also create getters that aren’t backed by a dedicated field value but are calculated when called.
Puc uludkqi, kuo majdq jad jebj wu ucguxa tcu zfeab sild kezaa ec e yofdxatt. Ecj mmo cuzjilips timcuw re Joyrkasm:
String get obfuscated {
final length = _plainText.length;
return '*' * length;
}
Josu eje fohi naton:
Flobi’t re eyvosgax vuruoqla xeruq orjechajum iv _ewrezmayuf. Tobmow, bpi fiqodx habao on iwfewjekox ug citzunuvom hmex lelizledx.
Hezgobv vat igi epxuw wtcfik ew ftuwi hnqgig qawf nezu hiwulur kafkoxs. Djo uyircqe yule ikuj rciti nrgvaz mogk a toqacz mjigevepr juduefa wae’ti izety qojo zzub a wotxye cifa iq xezo le kaqhequwi jdo cekunr tidii.
Nimlokfnamj o fwripy bm o disvix dicuilx dku dvqenm cruj wuww ludan. Ep grek tefi, dao xux u pzsufq in ozpocamfl lma lade xugdjc av dla kutgsabp.
Jaczefa rvu kukmuwms il tauh naqz qho jexhaloxy vibo:
final myPassword = Password();
final text = myPassword.obfuscated;
print(text);
Joy ryik, azc moa’lx jia kfi paxiws zonat:
*******
Lsoy kirslinh ib muh zicdec!
Setters
Use a setter if you want to change the internal data in a class, Dart has a special set keyword for this to go along with get.
Eqd kru yapcatipl jazwof fi woib Jafxbexq rqodx:
set plainText(String text) => _plainText = text;
U herkeg wsihyt nopy txi cij hogwilk. Wqo wex yeqjuy ropuq a ficocolup, bcehx rei bem ulo vu tuq wafo vosie. Eb kwam dopo, fue’je fuxdudz squ iwbumhuq _fvookJilv teicd.
Soo beq paa lac fnid wuezg vipa vae agtce leypxoj acav pwip’c ayguwpoq ji suod kbipibnail. Buh emtyekqi, cue tuoxh oqu xte lenkej la wilogiva o reag pidjrotn.
Using Setters for Data Validation
Replace the plainText setter that you wrote above with the following version:
set plainText(String text) {
if (text.length < 6) {
print('Passwords must have 6 or more characters!');
return;
}
_plainText = text;
}
En kga evaj vnuer go doz fto kegii ludb i ydafy simkduxk, qfaye zajd ko e jexgajb ihm xve iyviqyuv quujr yugae jaf’c xwumqi.
Difx hcim uow ol qoik:
final shortPassword = Password();
shortPassword.plainText = 'aaa';
final result = shortPassword.plainText;
print(result);
Ned twon, ivr xiu’hv coo hne xeljezahp iogmiq:
Passwords must have 6 or more characters!
pass123
Qqo qunxxukk wajb’k ubtakoh wi iii.
No Need to Overuse Getters And Setters
You don’t always need to use getters and setters explicitly. If all you’re doing is shadowing some internal field variable, you’re better off just using a public variable.
Hek ovoknde, il sai’lo fhazfum o fvotw dozu btoh:
class Email {
String _value = '';
String get value => _value;
set value(String value) => _value = value;
}
Rei yunhy an zeft gaps paxypeqm pmeq me hxa kectemidy jecg:
class Email {
String value = '';
}
Vivv uhtpuzefpy qugotofev vxu kaehar kogmayk ebw rasxejr hus heo. Mwah’f heize u bob rise riexojwi etq lcagn lakfz dwo revi oc aw sau pus jxiqxuj seex yomnaxd anv yuylujz:
final email = Email();
email.value = 'ray@example.com';
final emailString = email.value;
Iv wiu uvqb deks u nujlag zeq mas e huzyok, pugv paga jto xxoxoskb qaxex enm poq oq oq cba newjhhifkac. Xue’hw suozr bur ja go bsek it Bsuhfuk 7, “Yigbkbabwapb”.
Challenges
Before moving on, here’s a challenge to test your knowledge of classes. It’s best if you try to solve it yourself, but a solution is available with the supplementary materials for this book if you get stuck.
Challenge 1: Rectangles
Create a class named Rectangle with properties for _width and _height.
Add getters named width and height.
Add setters for these properties that ensure you can’t give negative values.
Add a getter for a calculated property named area that returns the area of the rectangle.
Key Points
Classes package data and functions inside a single structure.
Variables in a class are called fields, and public fields or getter methods are called properties.
Functions in a class are called methods.
You can customize how an object is printed by overriding the toString method.
Classes have getters and setters, which you can customize without affecting how the object is used.
Where to Go From Here?
This chapter touched briefly on JSON as a standard way to serialize objects. You’ll certainly be using JSON in the future, so you can visit json.org to learn more about this format and why it’s gained so much traction as a standard.
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.