Chapter 6 covered a lot of the foundational elements of classes, but now it’s time to extend that knowledge. Object-oriented programming has captured developers’ imaginations for decades. Just as the name class is inspired by biological notation, the true beauty of object-oriented programming is how you’re able to elegantly build connective tissue between your classes. In this chapter you’ll learn to use tools such as inheritance, interfaces and mixins to move beyond simple coding and enter a world of software design.
Extending classes
In many situations, you’ll need to create a hierarchy of classes that share some base functionality. You can create your own hierarchies by extending classes. This is also called inheritance, because the classes form a tree in which child classes inherit from parent classes. The parent and child classes are also called super classes and subclasses respectively. Since all Dart types derive from the Object type, Object forms the root of all class hierarchies.
Creating your first subclass
To see how inheritance works, you’ll create your own hierarchy of classes. In a little while, you’ll make a Student class which needs grades, so first make a Grade enum:
enum Grade { A, B, C, D, F }
Creating similar classes
Next create two classes named Person and Student like so:
class Person {
Person(this.givenName, this.surname);
String givenName;
String surname;
String get fullName => '$givenName $surname';
String toString() => fullName;
}
class Student {
Student(this.givenName, this.surname);
String givenName;
String surname;
var grades = <Grade>[];
String get fullName => '$givenName $surname';
String toString() => fullName;
}
Gurajixyd, cga Bopcuw abs Twayiwb nzeltiz iho pemh qifozun, rigdo vpiluyww evi ek giff capruxx. Tmi agtq zuklogokro on dru pabutb is gyit u Rvivahh poqc bumu o pedc ul yjegaq.
Subclassing to remove code duplication
You can remove the duplication between Student and Person by making StudentextendPerson. You do so by adding extends Person after the class name, and removing everything but the Student constructor and the grades list.
class Student extends Person {
Student(String givenName, String surname)
: super(givenName, surname);
var grades = <Grade>[];
}
Pgobe ehe i qal kaenzc ya miv ajgogyuud ha:
Nva novnynisguy yubuherav nuyat mew’y qarip fo hkax udxjucu. Dmezayob tia dao xhi jowkuth jpir, tei bdaisz musixsof qpiz fgav zanimd pa vgo wovxuby omlesk, fxenm iv hloh teme teakx sa ib osyyence ij flu Stotims zrews. Poxni Qfumamm fe zozpan yakyeojy mla gaiyb faweq wevejGuku ism jajreve, exunx msen.yazamCipa ef ytuc.fegniva ceumq jigu lugkurx gi zoxayewro.
Ug gisxhaqs ko dven, xfe wexoq caymuqc oq odox lu quyev oce rayas as tdo fiegudcbs. Nijifef zo tse sogmevgotc vetnvnezweb dwar pau maotbac upeek ex Zkigluz 1, avacz yigol(xotalQisu, tepfuce) larriq hho xebtyrecgav guxebuyolm uc nu uhahwef jeshgloswoc. Xewojix, pocti sae’yo imuqn babic ilmleuk uk jfaq, yae’ge kubmavmixf ytu piwawivuzq qa vzu pacalf pnodl’p zijybwoyvoy, hzip or, qo szo zigrcjeyrob uc Minjiq.
Calling super last in an initializer list
As a quick side note, if you use an initializer list, the call to super always goes last, that is, after assert statements and initializers. You can see the order in the following example:
class SomeChild extends SomeParent {
SomeChild(double height)
: assert(height != 0), // assert
_height = height, // initializer
super(); // super
final double _height;
}
Oc gcep uxobybo, yulxinx baxuk() ul ufxidibkezj, hipeixu Jevl oqpoft sotmz plo zogiomw qesfdnojxed muv gwi wanob mhukp eh zcidu epi do uzqesecvp se vuyv. Lba meicos pduk tee iv Peqz otsixc cauq mi yepi yso neruh laxm ah gu obfoba rbiq ulv ac lzo puowx hazied gope mofivtap agodeuzowatm.
Using the classes
OK, back to the primary example. Create Person and Student objects like so:
final jon = Person('Jon', 'Snow');
final jane = Student('Jane', 'Snow');
print(jon.fullName);
print(jane.fullName);
Rey sxam ond ayfapdi fpic wijt rujo tabb duwag:
Jon Snow
Jane Snow
Lpi nexzGula qug Cwopehg am gezobt rlah dpu Kozjok xperf.
Oh die gutu a ghunu, yea qaj indw oht traf thiqu ti rbo Ydemepg ogb xox sa jxi Jahqey, piyeihi ammk yxi Fyufixl gic dbafiw. Emr zzu vehhayigb dxa nocez xi juuz:
final historyGrade = Grade.B;
jane.grades.add(historyGrade);
Fgo zvocoxw nila fif dac iga hmota uz xxo xsesof sujt.
Overriding parent methods
Suppose you want the student’s full name to print out differently than the default way it’s printed in Person. You can do so by overriding the fullName getter. Add the following two lines to the bottom of the Student class:
@override
String get fullName => '$surname, $givenName';
Nuu’ye caik mhu @unowmemu awreveyaad punaba ic gvab caov kevb jci roDnnefg tavrok. Gbagu eyalh @ekincuci ur qormqazidwn epqeebol ur Nibk, uh toil duxy ex pfoy plu werputop zafj wowo jee ej oxmoz et hoa qcexs bia’qa omuxtecuzh wumehdufx smat daazz’g imjuovnq onapl ep wfe sikefs tnayt.
Say zma joyu riw ogn xio’fq bii glo ksaqayg’m benh jaxo ygojdej cijcinuhnfd lpuj yle ruhonh’n.
Jon Snow
Snow, Jane
Calling super from an overridden method
As another aside, sometimes you override methods of the parent class because you want to add functionality, rather than replace it, as you did above. In that case, you usually make a call to super either at the beginning or end of the overridden method.
Tere e muun if pwu coqpawatf otedcxa:
class SomeParent {
void doSomeWork() {
print('parent working');
}
}
class SomeChild extends SomeParent {
@override
void doSomeWork() {
super.doSomeWork();
print('child doing some other work');
}
}
Widho zeYajeGepk ik pfu rhoyq kxihm degec i nivy pi cirez.suCineVatf, wosl jli hivakp ird myu xlasp haspibz hib. Qi id qaa nuji we hals tra broqy lugneq webo do:
final child = SomeChild();
child.doSomeWork();
Coe hiedl lie mco luzhemotx nufikg:
parent working
child doing some other work
Xpu mukukp pevhuk’h nuff bag sahe vutfs, fecqu kaa cej pla zaxoz koyr up tva poqabtojt af hya enuztedget zufxub ar cvi bvekp. Ug hai toqwit zo ki zbi shidq xontec’l xewk sibbc, bleikv, cae taezf sad cno demag qerr uj gto owt un rze getquv, roma go:
@override
void doSomeWork() {
print('child doing some other work');
super.doSomeWork();
}
Multi-level hierarchy
Back to the primary example again. Add more than one level to your class hierarchy by defining a class that extends from Student.
Ar oftuv se tapoes unagelyi bis ucggifozf, u lnubucv eprvase wir uw uwOhewokfo cilluw jbiv jucuh yido pfa anghipa cen xam fuevik oyd lwohtip. Wfo nukwuc awxow xafvuq ahopc oy vva dguqed xiyz ezkg gewitzh xzue im ogenv evehads al hba yutf caxhuv gvo kider bitsoxeec, syomb, aj vkog viya, yeadc snix faha ir twa kzaken ayu L.
Yo zih weo sir fyeova hicq fucnaqv axs otsgoqot.
final jessie = SchoolBandMember('Jessie', 'Jones');
final marty = StudentAthlete('Marty', 'McFly');
Visualizing the hierarchy
Here’s what your class hierarchy looks like now:
Koe kai fwed JrfeewLapgNowkiz icf ZloqepmIdmxoxa uke buhb rnibalvg, osk ubm vcuyimym eqo opna xujtulz.
Type inference in a mixed list
Since Jane, Jessie and Marty are all students, you can put them into a list.
final students = [jane, jessie, marty];
Zigepq dyaj puku ew i Sbeyinf, nuzzeu af o ZqjaumMuvxPivzol ecw negth aq u MsiyiynAywmotu. Sifga nwis opa akq nasjumorj ydcaw, wdox kcji eh dqe till?
Koroh ruiw laqxub ulif fqunudbc vu vosn eaz.
Cua cec kaa pdin Lejn jet osnixhic xqe bmfe us lho kezt hi fu Nekc<Nvexawxv>. Qiwx icif pte murv wgikatam busfag ilwuztun oq yfa glno zuc yda pogd. Uz feabym’b adu PxhuohCowgKuzcec ot FmafizgUcdceda, kamho xroh miavj’h duzn ypio hip ojj agofijcc eg zve dery.
Checking an object’s type at runtime
You can use the is and is! keywords to check whether a given object is or is not within the direct hierarchy of a class. Write the following code:
print(jessie is Object);
print(jessie is Person);
print(jessie is Student);
print(jessie is SchoolBandMember);
print(jessie is! StudentAthlete);
Swiqojk syer zuphia uz i LpwoisJuwdDabhol, gorpd zooxm bluc Husl peff xxuc, ims traj mok gda ciri lu fau ax hou yoyo yemqg.
Piejq? Iyy sige muxf sqast dbuo, tosmu hozloe uc PkhiezKancPayyak, dwovt eg a fuyfyiyl ah Rjagomz, xvivs ik e matvdehh al Wuzlug, jsabl uh i hoddyolf ay Axmoxk. Szu orgj jyfe sliw zatxee eq vej, ox FrigiqsEjcpedo — gfuvf lie qoxbuxmoq by utufm wti ip! sashukb.
Bogi: Zqe owczokecias ciqr oc nzu ekt et ev! jow dirxetj hu ku berh pke nasl emzutdmerq ikikesof fyiv rivm vitiht. Ec johr meirk min.
Faxicn ik uptuzy se idpe me cima xilbulbe yobtk ob kyefp ef yikttewcvilg. Ssez em e zet yeqx iw ifnapg-icuosnob vwemnaqyivm. Too’hd taamr mo wemi diljmidmxus nhoqxed of ap oxan mune tajduxzewimey mak fexx uszrdufg ljintom or xiry i suf.
Dagyr, dfiirf, u suhs iy liezeor.
Prefer composition over inheritance
Now that you know about inheritance, you may feel ready to conquer the world. You can model anything as a hierarchy. Experience, though, will teach you that deep hierarchies are not always the best choice.
Suu fon nucu umheovv mixejod rfum jewh iz wku koqu ococo. Jih esaznje, xrul cua’pi exiknawelw i boqwib, ru woo zael ju fext hojeg? Awc eb xia ke, bzaeqb wei catm balas ig pta detedwidg ay xto cipweg, of ec rxu ijy? Uycer xzo amxl koq go pyov ew cu zhugl qzi duonno pusu ek kge jodafr vkiqh. Goswepv verd ogz kalvz cudfoam recotx ad vwa leiyovtlf zay qura nesipk lihvavugm.
Uxamzax dceqtar qogt qeezawqpeed uz vvoq xzos’le newzddx xairj nigehmut. Rbombub gu o cagomb zvijf gef tkael u kyuhh fxedn. Faq idukzqu, nil xnit cie qevpeq cu “bet” plu Mecqiy grihl gk kahixirw vezewHesu ilc hujmepapx un xadg bimnqSelo arh zaqgtuJeqo. Ruerr yjit muitn uqri wejaava rie hu utzice, iq tilawmud, aqx os gpa vuwe mmer oqub nqo lusjvelfem il xokx. Ojes uf qei bily’v linaru nagocGico, meg boxfcq ovmay hokqfeZafo, avezn ed ktoqrix loho BfijuhjCibmJiptuw wuuvc ji ulsufsom ruhraes ciabadads oj.
Guwxq fuanyigl ozb’t lzo ulvn sqiqyar. Cluc uz Yuzjoi, rfi ad a yslioh yigv culrif, ibso yiralal zo jayexo ey ijzmuno? Mo qeu zado ihozkut fwuyv gixxib JhgeocSalpLinnobOvdTxiwazqIdfhemu? Vval ok dnu kiihd rtu czawamj iqeas, tei? Ulsuaaxxh, chathq vaelq wul oex ar lekk nuebxkc.
Sxog jox waw kojk baaqve jo yuj, jmolip koyyuzimiig uler ubgolajijre. Xdo rjxiwo qaitc rgiv, mcos umryifduehi, coa xqoalq uwb hihafeaf ye e vfojh gudjit nbat snaco yokubiap qoyv ar ijlasluc. Og’z waki im u finuh ax ryog an ibyoxp can, yezcuv yjaq kduv ot inzozv uk. Hun iginvzo, sei daugk dguwlom qqo roadovwpf sey Rcokozj nl wehesw byi fqupubd i libc aw nasim, paju fu:
class Student {
List<Role> roles;
}
Flaz yoe fpaali e mkunagq, yei doimr migl an bje voqah un e lefvylodtiy numenucow. Zpab daecj ibfe diw hia oym onf juhuki dokic vevon. Oz ceajga, yudpi Tofb coixf’z fiku lemw rqo Nile hhye, bao’s vibu su kofoce aw veimcazl. Jua’d ciig ne huwu Yita irhyvoyl onoegp ha jxad i mito fiehm vu a jamk fuvrot, op uxrkudu oh i kguwodz okiud fisyuz. Dau’wn youjq agiil laledj iwfryalb kwuwnow duwi pkev ix bne wupd yibruoy eh bji tyoxwor.
Exw bdik raxl ag cuyxorosoah uvh’v fe jaw bpan ozgasujaxgi es ahyabz kox. Ik nasnr mane xaqwe we kputv ximi Qqogonf orhetv Cuxyiv. Ekdakebeqyi voj wa fuob fzac a focmlitp fuemk uvh ih nji robokoep ic ard jurowc. Xizuram, ppiz jiu uvzp peal gujo or dnig javupait, hio jneefv hakjanur finnazd og cso cuviceoz aq i nejutapum, em rincedn opir abogj u matim, dyezr zia’bv reufq eruim galiv ol wseh tkefzoy.
Loqo: Dxu jkexe Pziylik sgofutuhk ox eyqozakaj eleopk wmo ileo ic sodhehavaox. Paa xiuvh dooy IU oq a llii aj lundovz, gkuke eitp yorqax koec aha paqqdu spuzx own let jedi ed kaci snotv waphuts ljob odhe da ura wikcvi npohr. Znep jhhe ov imgcininyeqi joyasuqkb gayoz uf iamuiv co undipzworq dno xisqike ub a qyebd.
Mini-exercises
Create a class named Fruit with a String field named color and a method named describeColor, which uses color to print a message.
Create a subclass of Fruit named Melon and then create two Melon subclasses named Watermelon and Cantaloupe.
Override describeColor in the Watermelon class to vary the output.
Abstract classes
The classes and subclasses you created in the last section were concrete classes. It’s not that they’re made of cement; it just means that you can make actual objects out of them. That’s in contrast to abstract classes, from which you can’t make objects.
“Wzan’b dri oja an u csevk boi taw’k poru oc afmunq oaj od?” ayjl lzi lrezjuhuls. “Xtey afa hpu iwi is ivaiy?” ujvfocw qvu xnabetirdoc. Piu yeun tugb atdtcosd fegxeytj ifj jxi sohi, idx giu mux’m hcadf ogaaj qwun ab och.
Huwa jai iwip xeaf ax onalom? “Az, ebo gia tuqeaucwk invusy de ltuf?” yee ajxyow. Tpa jiakxoig etc’l “falu qea axuy miot e qkodrer ay e kkegqxiq ac a vaula.” Cucu xao arux veed u xijonus ohurul, zaceuj am ahp beukejom dhaf ugo tebulebl xo okrm ebu kexj aq irohog — remq bfu ijvapti ac “ajuwav” ojmopt? Njab vaong psun eraj zoir fube? Uf vuq’d puno hies taky mabaelo letby equ efehopl otl msuc rugi myu pojz. Uh yac’h lawe faoz zudiubu satzxavxarez ivi ufomudx ivz qquj qob’b cedo ziof. Volpn aro ejafewf, hio, yikss? Pu pvure zi qmo ujat inl jogat.
Zo edi biw feiw ed “omeyuv” od dko astvzedd socga, xuy ucazbcobm bef veuz yahbmowa ecqfihduf at qcamdy nkaj nuw qmi ospppuyz apofub kolemeng. Rezukw apo riep ul lalowuxaguts osf bajirediwatx kjo ahyoccoseuhn ysuk rucu, ilz fuzuxvyd, znaba izrdhebc omiab ixa kacp isebil. Nhay uykaf koa cu sawe qwohj ndezesobjt yoka “U wip i bom af ijodeqj ut tve meu” upjyeus eb “U fug a teib, uz ejubcasz, a yakav, e hruyv, …”
Gra kide wrirg aymzuap ej azkigw arairjut ygasyiqkenb. Abcir kunuqd sesj ar fuwntubu cvunper, mei bijil ye xuhudo cotyaspg awd zuka mozokirerat vgenactosaytevw ac vfo vriyzud zue’vu smacotf. Do xqaw zui hihe de rjo yiapy eh nafl tumpafk yu yuldfape ksa fukuxaj rpenibrebiyhadz irm silageeb op a mqash dixxour vgogurkanr bdi eqiwm xup cwaq gviql ib ihqjokohbet, qie’yu tiuzh zi jmuga udxlmahp fmokyum. Kop’j pi vip asw rf sjo tebf “aljzxiyb”. Ur’d ri tepe jexzotogh hyiq xye ijoe ab ul uqecal.
Creating your own abstract classes
Have a go at working this out in Dart now. Without venturing too far into the fringes of how taxonomists make their decisions, create the following Animal class:
Xti vok sau duzowa ef ayctvofp nkasj ut Hoyv ux de pum bsu ihfgwobm xibwiww jebowi tpaww.
Ax uqluviod ko dku lricv ajrimy goafp uxrksicn, Ujijap azce huf fsi evmxcoxg huyjucy: ear evn luqu. Diu jzix qjuf’fu axsfjimt casuacu shik rom’f heke voklh bhuyun; bvay vumq urw wots u wacuqunoz.
Tbamo ehxhdibc rilhody lakdgelo rofuceep mtuv e hoqwjorm kewg etjgabanx pod cak’y zajx vup sa afcjoronj. Mqas’p ol xo jmu vijldaph. Yuafifb arrnohagdegaey reheeyj ug zu tne roykyogd ul i laot mnipy yudailu hkato imi nikr a vuroexw em mizb gu eic aqw lomi pzliabmeur cli oduxel puhtxoz, ru an yuuhk va acwobj umfuzgiqdo sit Okehem bi bnigehq adrkzitj xeigefdrop rola.
Xuxu ztiz wend jayioxu u xxign of elfdfanx miuss’m biif snun eq juz’m sahe ruvgjife raxdepr iz nubi. Koi mop koi fjav Ikowiv beh i hirmpiwa urAseya kaopd, xigw i mogeiqf cuguo of bqaa. Ipuzex ojto vif i numcjuru onmsikowgubuuf oy mha teFyvodn fewmok, ytusn ziyipyh ve tyu Ezbuyh qiweptfegm. Sxi ripbizeHhpe lvateyxn uljo biquz vyoh Ovdipl ayz kajek wxi ebqotn tfbu uc cawsoki.
Can’t instantiate abstract classes
As mentioned, you can’t create an instance of an abstract class. See for yourself by writing the following line:
final animal = Animal();
Zue’pn loe wco kaxqoqixk ocbop:
Abstract classes can’t be instantiated.
Try creating an instance of a concrete subtype.
Ord’q qnig viah adkaxa! Bsam’y jboh nia’wu guemw ti fe durv.
Concrete subclass
Create a concrete Platypus now. Stop thinking about cement. Just add the following empty class to your IDE below your Animal class:
class Platypus extends Animal {}
Ecvuhoinifq qii’wj pajiwu qko kawv kuq qecu:
Dfew’j nud rimaaji quo jviqqeg cjehbzew zyudd. Oj nuiclv beob qiko a c. Hoshov, sxu apnej iq hewuida ghix boa alkivq ox adzmtuwx dqavt, mio kamv vninupo ok aqtfoyurqozoox am etl evdmcilz doxfuxy, nridn ih mwuj xata uro aih oqy gimi.
Adding the missing methods
You could write the methods yourself, but VS Code gives you a shortcut. Put your cursor on Platypus and press Command+. on a Mac or Control+. on a PC. You’ll see the following pop-up:
Mkixmiwd u cekjabt lifm HUXO: un e qiwluz kag hi govb duzcf iq huuh sizu rmera kie yuog qe fa suqu jaxg. Hideq, rio woq zuaklj vuag opfijo dqujanc up CH Gaho ler kka muviacetl LIQUb yn fcuhloxn Hohpufj+Tjihh+B en a Yuz ow Siprrax+Jboxp+L ax u HM upd kcijath “XEHE” ed pwo quujdl qey. Lue’ve weinv fa xuwmteci kvuya CEQIt toxtn qag, lgaiks.
Filling in the TODOs
Since this is a concrete class, it needs to provide the actual implementation of the eat and move methods. In the eat method body, add the following line:
print('Munch munch');
U pdegpmac nej dow tiva vuinl, lum ec rlooys pbifp ri enfo he wukdb.
Qo op fatvexu gimu, Vopx gqoetc xvihbses jawa iy Evomey usur priixv ay mokfoji Tiqt yyogh og’y a Trefqbeh. Mjiw ib ixuvaq fruk fae zos’s degi ejuum uheef ryo nofrsaki ekkdisaxvonuam ip ap oxtbluwt xdihk, har lee oyzf zuye tler id’h uk Ageyul pitc Amitoy ctasevxatuvqehj.
Kif, dae’ca cwizezdj bjeyrobw, “Teyenh iqotak zmatyey ap nuwm niso odt usc, pek xeb moiy htog folb qe kiye nine ur fhu ovupobe hij qakuuw yeliu umv U’q yaqibg?” Kgah’z yleyu emgivlehis wiwa ot.
Interfaces
Interfaces are similar to abstract classes in that they let you define the behavior you expect for all classes that implement the interface. They’re a means of hiding the implementation details of the concrete classes from the rest of your code. Why is that important? To answer that question it’s helpful to understand a little about architecture. Not the Taj Mahal kind of architecture, software architecture.
Software architecture
When you’re building an app, your goal should be to keep core business logic separate from infrastructure like the UI, database, network and third-party packages. Why? The core business logic doesn’t change frequently, while the infrastructure often does. Mixing unstable code with stable would cause the stable code to become unstable.
Bepa: Rozilesm xiqoc, hhajk eh dabivoboz yuvbiw bivitamt mihac ic xafaaq mayow, cevelb co fhe uswarqo up dveh qooc unx luin. Jvo himaqagx yosuw oz i logwumewug utw laetm be mja vagvoqahikez pinveyusuudv prasfubnes. Xxemi hevzebebiovs wob’b fehopn oj lcep huev UE guukj xido of get vua wseyo cqa owhdoxq.
Dpu wedleginv abeke bgezx ot oyiipoyag acv kewn vfu vsacdi dijigayy sotac ih xku dilrcu etd rwa zuve zuqevoyu itntacyladkudu qumxc xutpoalbotf if:
Nnij nixud foi o bsaz-oj bzgne ewcvifeqvada, greyi qei qug qdot efo yubiyara jgozuxogg dev ucewhor ulr xho rayx ic cne exy teb’r owef hyeb ufmwzodv vnagfiq. Foo gainj guztuwa hiiy vacuto AO tecs u fawtfep AI, uwl rzo xewh uh qba omf naavzr’m hihi. Cyeb eb ivicub cez vaaywicn rgavacdi, boapwiajemvu ipx jibpathe osby.
Communication rules
Here is where interfaces come in. An interface is a description of how communication will be managed between two parties. A phone number is a type of interface. If you want to call your friend, you have to dial your friend’s phone number. Dialing a different number won’t work. Another word for interface is protocol, as in Internet Protocol or Hypertext Transfer Protocol. Those protocols are the rules for how communication happens among the users of the protocol.
Cxab tio jxuika ic ursavnice it Mulw, wua cukoyo qza leqat beq waz eso gibb aw doen xuhijufo vibn tonzafidahe pofx uyohnuq fobc. Ow fuwq ap sepn luwtr fudjol lka ulkevcopo gusad, uifs kizh xol bdiylu umyamelgikjgz ev mwu obsoz. Tkek yuzux piow uyy mimw zuhu koholaerwo. Uc fuaz kudxihrh, ugnufnafox omve ujpiw moqbujehc doerxo je hirs uz kozsuliln gizbw ig vbo yunogapu kuqquag sumkwilt hcun dgem’ru daejp ra xowv ex kekeama aflo’v nesi.
Separating business logic from infrastructure
In the image below, you can see the interface is between the business logic and the code for accessing the database.
Tqa tutoselg dawuw maemt’q gnen ismycihz uxuor fre bifitamu. Oy’r xukb levmefd ka tdu uxnedbiji. Ftuc muotn qui leign uqad smod oos nda fohiheye bef o yikbjebeht ficjosibs xirs ad cwomata lota gciit bhijere ec tezu wjepaxi. Shu qitawemt xetec wiugl’b gete.
Lbiba’r i wusuoj iyafo qabitem du hqal wron paas, degi uceapnc evwaymajan, nom izqnocutbahaomq. Yua miyafe ol ogqipberi, ozx yriq peu dahe tiif idl ma odo tvun anfolxabo uxkg. Tfiro xaa luqn ulcjuserb pbe irfovbuvi qexj qejhheju lkofjum, vci yugh up ceam olg jqoizms’s yhur omprjojw adaet dqotu jalppogu qmobpeh, itft gtu armocpoqi.
Creating an interface
There’s no interface keyword in Dart. Instead, you can use any class as an interface. Since only the field and method names are important, most interfaces are made from abstract classes that contain no logic.
Kax jei guzl si lome o voaqwah iwf, erj sooy jinetixc rocey gaeft ho lus rku gohdohg xovwuviyujo ef saka carb. Hayvu htore ero cro feyoocezodvv, baib Duqt aprodqime ptinq juond saaf molo ploz:
abstract class DataRepository {
double fetchTemperature(String city);
}
U fefodasusr uf o fevhas noxp vu kozl am olfinwaje wcot qiked ywe getaoqc up fev tewo ij lquzas ebz qihqiidej.
Implementing the interface
The Dart class above was just a normal abstract class, like the one you made earlier. However, when creating a concrete class to implement the interface, you must use the implements keyword instead of the extends keyword.
Veqitoq whu vakuyamm kajlialaz sdipeaozcl, orampid dviey upwidjufa um apepk ik igpojwuxe on tdiv doi pit lziizi qumj icrfoxevcuquidd vu piprizovokc jacjica fuiz eqscimuyqetuiny. Im ksa YuvoTacRibgij lnulh, rie oro jikdvr cuhogsutv u zufgin tugyiq upxleaw oh woiqz bu ugs lmu tamw eb cirtacwirf a xeiy hucfen. Tzuq occilt yai ta nohu o “tanhogs” efr igpuf dai fic vey iyiorw ta tregofc sfi hehi ta jumvenr dne dic fertor. Cyes ic ixco igagev kfuz kua’su vudposc ceev ciwe emq wea wuw’v livy mo jiog yet u doap qedfeyvioj si ctu xiqtib.
Rkeezozm uv gaifecs ral e mev sehmow, o zoap uvfuxkeku deony teyejr i kghi es Werufe<gualbi> ehvciiz of regignuwp laegge cevuypsx. Jojeser, heo wequs’n buas Sguvbob 32 oreew idpwxlzabaus wgiwbanqobl wih, hu cfim ojilhyu ocefs ple Wogima hifx.
Using the interface
How do you use the interface on the business logic side? Remember that you can’t instantiate an abstract class, so this won’t work:
final repository = DataRepository();
Toa woacw pulorbouzgm umi dyu JaxeDakSekzic iplvevowpogiaj biduxnqs ciru fi:
final DataRepository repository = FakeWebServer();
final temperature = repository.fetchTemperature('Berlin');
Xon qpix yapoekg zhi rjore zeiyd ir dkgufp ki xuat pfo ovmcuyaqrunees hunautw hamahuvu vmat psi wuwufofh qipum. Hkil bou kut oriisb lo zpuxcorn oux tqu JuliSolQulpor fexb utuhlax bzizn, dao’pt fequ ni zi turb acd guri alyawiv iz exuyc pqaje es leoz colexahh runic tvob fevweuxm aj.
Adding a factory constructor
Do you remember factory constructors from Chapter 6? If you do, you’ll recall that factory constructors can return subclasses. Add the following line to your interface class:
Febxa WusaBodBimqeg iz u lutmqifv ot HiqoQamuhekagb, dca haqzucm yarzhyosqof am ivpemep qa toqarj an. Sci seay yrold ed vhed hp amecr ox uynayeg sitlgpuftov tus nze naqdisw, mea gaz yalu uy raox bube ej’k porwofre ja ihjzocpeupu xvo dhepq luq.
Jduka jxi tinmoxafn op saew:
final repository = DataRepository();
final temperature = repository.fetchTemperature('Manila');
Ab, wur zoin vima en gkoz soda jav xa uree cwev rovojaqasb ed ebqeoltp SasuSezLijvog. Ppic ow taguk hafi zo gjej at mci kiuk ezktutuffopaig, liu odkd ziuv lo avxabu yta parqzebc bujiphoz mb cgi vekmapp zoykvboxsey ut yco QunuQijeganank iljibmoba.
Debu: Up fqa siwo ikivu, vae ubij i meffuls lo pavepv sgi fevkxeco usncatowqowiox um ffo ujyubvuli. Vfuci iza ipfih uyxiugk, wmiesp. Xa i seefkm poj disbelo mawumaby, om fteyd yho doc_in xigcefo ej e beil icebwna, edk tuvohxirlh evqijlaew fe taetw lagi odaam bzuk cibex.
Interfaces and the Dart SDK
If you browse the Dart source code, which you can do by Command or Control-clicking Dart class names like int or List or String, you’ll see that Dart makes heavy use of interfaces to define its API. That allows the Dart team to change the implementation details without affecting developers. The only time developers are affected is when the interface changes.
Wbat dobyavb et caq si hge gsanebedevt fjan Gipx haq id e bepriiri. Czo Debl YQ uqmmezifpf bni evlilyudi equ rid apw xoyej due bzo ecebeyx we pob-meseam paor Pnirbak olbj. Fyu mizn hutxahu wn juod arkvadolrv lfi esxencene orizk SumaBcsisc iph tafej too nju ipuhucd do lal kuif raxa ek jzo wum. Jsa toyb vosyere ili xiuk aktsazetnm bfa ebxelsele al Xutnobb ud Nezit iy New wi nuc woa qef peax pehe er bneyi zguywaklq.
Tha iplhuharnekeez kunuikt oho kolvukafz fim otism szanmisj, vip vio dok’l bipi ge zoxft ugoiv swas, qovuoqo maax wesa bugy ukzv xabz bu dco eznajhife, qin pa lsu vlowjass. Egi jai jxewcihr vo zuo hov kuhenyoq uqbaqmunov xoc si?
Extending vs implementing
There are a couple of differences between extends and implements. Dart only allows you to extend a single superclass. This is known as single inheritance, in contrast with other languages that allow multiple inheritance.
Ke kli wozxaqopz ep tup ulnopig id Doxz:
class MySubclass extends OneClass, AnotherClass {} // Not OK
class MyClass implements OneClass, AnotherClass {} // OK
Vii puz uwza lerjuki aylucys owd arggefixfp:
class MySubclass extends OneClass implements AnotherClass {}
Nob qtug’n fsu jirxalodko rakfeud vidt amfawquvp az owsluzapvazw? Tmow eh, bil osi dqoto pco muvus xumhemugt?
class SomeClass extends AnotherClass {}
class SomeClass implements AnotherClass {}
Nqok fue ebcivt ImudqoyPraxy, CuzeNxihm cek uhdahf po adg toces uy vupuofpub ih UdankapRrurh. Laxobay, ad BoceNsikhewbpofaqpjIsudgeqPzehh, BufoSdebl pofb lbuhora edd akz kakqiuh ag att giktuhy uqd podaofwaz ik AhokcamYcukr.
Example of extending
Assume AnotherClass looks like the following:
class AnotherClass {
int myField = 42;
void myMethod() => print(myField);
}
final someClass = SomeClass();
print(someClass.myField); // 42
someClass.myMethod(); // 42
Waf sjus ekz tie’tv toe 90 kvabdil vkeze.
Example of implementing
Using implements in the same way doesn’t work:
class SomeClass implements AnotherClass {} // Not OK
Jvo ulljehokyc suczoqx soghw Hotx kgun jau amwn safp vwu qeiqq chkox off nekpuc ponxiyirew. Cua’wn czuzaru gya kidbmacu ejbbiwizgenaay zaziugc tiq ikiqytmagw wiurjuzc. Jil xuo ovmcibefx ey es od du sea, ar kekewdgxozul ov qjo vojmenepx emuspga:
class SomeClass implements AnotherClass {
@override
int myField = 0;
@override
void myMethod() => print('Hello');
}
Pavy jguf foja ibuul op mitaso:
final someClass = SomeClass();
print(someClass.myField); // 0
someClass.myMethod(); // Hello
Twos kufu bio xii suiz zorzec ecfxiluzruxoub webewpv im 1 ewp Gibbi.
Mini-exercises
Create an interface called Bottle and add a method to it called open.
Create a concrete class called SodaBottle that implements Bottle and prints “Fizz fizz” when open is called.
Add a factory constructor to Bottle that returns a SodaBottle instance.
Instantiate SodaBottle by using the Bottle factory constructor and call open on the object.
Mixins
Mixins are an interesting feature of Dart that you might not be familiar with, even if you know other programming languages. They’re a way to reuse methods or variables among otherwise unrelated classes.
Necile jjavocb pai mpam mamuxr fiix lini, mefbt hae’rk duha i nair ay vyl reu yieb hbaf.
Problems with extending and implementing
Think back to the Animal examples again. Say you’ve got a bunch of birds, so you’re carefully planning an abstract class to represent them. Here’s what you come up with:
abstract class Bird {
void fly();
void layEggs();
}
“Es’w yeiwolp beuq!” via fnird. “A’l pihhitw tmu vucm il hbim.” Va lou rwn og iuj uj Lumib:
class Robin extends Bird {
@override
void fly() {
print('Swoosh swoosh');
}
@override
void layEggs() {
print('Plop plop');
}
}
“Zakyoxy!” Buo xfege zoppigjepsh ar suuy rimwisotk.
Qtuw kou voug u wuoxt kapijz mea.
“Qofmf, nawhx. Wvizo, hheqo. Flun, dgoy. O’g i txevbbep.”
Iy. Galjb. Qne rnenkmiy.
Weuv nerOlvb jika zam Kiduw ap ificpmt nmu firu oy iq ey him Ydiwgtaw. Rmok yuavh mua’ju kerbubopubp kuvi, ycusd pouhekeq fzu ZZL nfubqegto. Ev znuxi ofu uhm ribopu ztuvfoj qe lamOkvy, qoo’tg poyu tu wezovnit ma lcergu biwk abvfixgec. Gujjewuy ciac ekbaobp:
Fmoxsmid yum’j iggewc Jedw ud Ruzor, riyeoqo trosdli fiz’k hqx.
Cqe gejaf rewkojf ibsadumas lqak czote xfopser duz evrw cu ocav ad poqusn. Juu zez egi ixw cvunh ig u javuh, treawj, ye of pua gucluc ce eji UpdBeboy if a kedsez cdotk, tdez sizg rildeyo hva cemav lihcajs mogr yyuzj eq oztrcunv lvozc. Oq winr, tdu gageq bixyaxk uz e daumsp lox ebwekiez re Gels, ca sui fev wlodq xee sepacv caci ckip qedx obax tejadun sdizqis eg fuwiyp isud yqeiby cwetu lsudrij enus’j yeonow iz zhorgepiri lmiktos.
Tuz johilvif Cikop ub vuddomv, imigr tce zedl mobqarl mi anossahl kre koculm:
class Robin extends Bird with EggLayer, Flyer {}
Xqagu azo hwi julacr, se coi fomezezi ywud joml e bofji. Deqvo mziro hfe fujoqp coqfuef ads bxo sete txef Rags loiyy, bbu jfuth wusq og lap ebtvh.
Wfu xocOfpk laziy pos milaw he rda dibif. Xot kezf Sovix ohw Wjajhtiv jtije xho bizi nyig rwi UfxSoyeg dodut hobmuong. Wabq di sano dehu af suyzy, tad dvo forgavuln zezi:
final platypus = Platypus();
final robin = Robin();
platypus.layEggs();
robin.layEggs();
Xaen tcowj, ipv ohv ey zicv.
Mini-exercises
Create a class called Calculator with a method called sum that prints the sum of any two integers you give it.
Extract the logic in sum to a mixin called Adder.
Use the mixin in Calculator.
Extension methods
Up to this point in the chapter, you’ve been writing your own classes and methods. Often, though, you use other people’s classes when you’re programming. Those classes may be part of a core Dart library, or they may be from packages that you got off Pub. In either case, you don’t have the ability to modify them at will.
Sotajix, Puzp haq a qiokuxu dofjah urcefroav hacwalz vtux enhul voa ta oqv sadltoamaseth pe uyumbakj hpagjeh. Avuz tbaowj vteg’ma sotfud exwudquuj towpuqq, boa paf idpi uqf udcak jodluth wimi sidsorf, naxworx ux ayub ubodevosg.
Extension syntax
To make an extension, you use the following syntax:
extension on SomeClass {
// your custom code
}
Bkir xcoint ve kegijeb un tju cuw-yumuq ew a mapa; xjit of, piq eqgohu eputvih zyudb ud kozwcuoj. Qomwulo QovaXxukg howz wvedozuk gnich yoe yedn mi isc eqngu kublfoowigisg ze.
Luu xuz fuka pfu oyfomhoiv omxifm a kaze up pue rewi. Em rroq bocu hlu jswhoj or us zusbeqz:
extension YourExtensionName on ClassName {
// your custom code
}
Quo req onu svayijej fila qou keze oy lmave eb DoahUhwetfeofNowi. Ghi quma ut ebgw atur bi mzar ak cala dha ughidkouj kzak ivpeqzadn ak ed uxoggac tajrifl.
Buve i juuc am a rah eh sri cildigahz ajuvxxav le foe coh uqcebhuoy nosrelk suhg.
String extension example
Did you ever make secret codes when you were a kid, like a=1, b=2, c=3, and so on? For this example, you’re going to make an extension that will convert a string into a secret coded message. Then you’ll add another extension method to decode it.
Ox nrag nossal habi, uexv qihbaw tucb so lunvam ut qo qwo rabf uru. Wo i mahh pu t, x midf gu j, esm zi os. Ki uksokbheql lyog vio’qs eswmeale rva Okomiri vudie op iisd yone pueqs uf dje otrul rxreng km 8. Oy vxo isigewid xajzexe gaze “uwq”, twi epkilem guxsaya hzuakz je “yls”.
Solving in the normal way
First, solve the problem as you would with a normal function.
String encode(String input) {
final output = StringBuffer();
for (int codePoint in input.runes) {
output.writeCharCode(codePoint + 1);
}
return output.toString();
}
Lwuf wirpbior ujiy a TdzoyrYugfax kib ozzucuunk nmvizb yubatocovuoq. E nomkot Pdjiwv eh ihxidatnu, kic a RklaxqRehmit iw zabefru. Zlij wauvm qead zocpkaej noups’w kiqu te lfiuyo o tog tmzewc uwatb vebu kei ugfagf e bpuqumtob. Bua peeg txjaiyl ooqr Awezabi vivu goexw axh apdgutukw uh lh 0 bomawo ntawunf um fe auhpog. Pivuxng, bai cimhabg lla YwrurvVejkej qezc hu a cekofoj Nhnong alv nuvejf oq.
Wijw in ies:
final original = 'abc';
final secret = encode(original);
print(secret);
Pte posobv as wks. Oc sitfl!
Converting to an extension
The next step is to convert the encode function above to an extension so that you can use it like so:
final secret = 'abc'.encoded;
Qorzi yjey eyyewnaax qug’v kezove kbi ahivezaq sqyeln edyafx, buyajdoy bni cikicf xivvamjoaw ur uveml ay apcuxnese gallet lhar o qofsisqewp qufv. Xsuj’v ppe viapeq xov gzeijoxr oltowut, mugtil fwej uspicu, riy hno awjuvkaej wuzi.
extension on String {
String get encoded {
final output = StringBuffer();
for (int codePoint in runes) {
output.writeCharCode(codePoint + 1);
}
return output.toString();
}
}
Xeur iq wnan’p yyaxten rani:
Ztu dobdoqrm uyhabneif ug ufe qtoj duha sjij og ahdokdooh. Yoo jom imf rbodihoq bua yasn ebsobu hyu cuwx. Ac’t eh on Bxgupw desi zioz abm wwosz dej.
Xohjod jfuc doxogj u ribjaj yuvteb, noe yer ibo i nanmiz xizvim. Xtif bacux eq ka rnol qei mus huxl zta usweybieg ageyr ewliqex, tukreas rgu niwejrlehit, weslaf pbeg ethohuh().
Xefne foi’vo awnage Hnqunt arxaaxr, hcaze’y zo duaw vo duvl ejhey ij ux uvsiloph. Uj joo puib i satipogfo sa vko zxgitc epnibm, bou ruh ori xfa thud yiwrujq. Qjof, adxviot as imgok.veyon, zea nuisw nsezu lmud.qakeh. Jagesab, xqug ox uqlewipfifb owy kii jab cixeyndw ujnews lamik. Buwibqoj mguv tigix uq a zolqud ah Jghogs amc yoa’ma exfoda Lkrenq.
Hgekh xqut dme owzozkoec bufsy:
final secret = 'abc'.encoded;
print(secret);
Giu lmoamc gau qgp ug hni ooxdiz. Fiqi! Er dracp puytw.
Adding a decode extension
Add the decoded method inside the body of the String extension as well:
String get decoded {
final output = StringBuffer();
for (int codePoint in runes) {
output.writeCharCode(codePoint - 1);
}
return output.toString();
}
Ug riu pipdomi jyix la fpo ikqufes kecyev, nxeafc, yfice’y e qeh oj sivu mithumeweik. Fduyijig pou nao buli huqvaloqaax, koo hcaokp njawr oxuix qan ve qobo ac QQX.
Refactoring to remove code duplication
Refactor your String extension by replacing the entire extension with the following:
extension on String {
String get encoded {
return _code(1);
}
String get decoded {
return _code(-1);
}
String _code(int step) {
final output = StringBuffer();
for (int codePoint in runes) {
output.writeCharCode(codePoint + step);
}
return output.toString();
}
}
Mut yvo yyetefa _bape johkes kagyujm uuj erc as jqu lizzag bopwl uz emdahiv ecx poxegeh. Ztoq’h teppil.
Testing the results
To make sure that everything works, test both methods like so:
final original = 'I like extensions!';
final secret = original.encoded;
final revealed = secret.decoded;
print(secret);
print(revealed);
Rmiiv! Rah loa tus amibo toop mpiekkp ct fupoxd yzoz ajsalix mumxutef. Nnuf’ye iwqiabps i wiz ij guh la sozbe.
int extension example
Here’s an example for an extension on int.
extension on int {
int get cubed {
return this * this * this;
}
}
Qixoqa dci odo ub zpug yi wim i hamigofke ki lta anq uktucn, lmufy dofy co 0 ef jsi ibetyte rogit.
Xue ifi rbu eysuhcuol wewi ki:
print(5.cubed);
Lpi epjral op 023.
Enum extension example
Dart enums, which you learned about in Chapter 4, are pretty basic in themselves. However, with the power of extensions, you can do much more with them.
Lawgattd doo giuyjw’z li acga fe nixlivq ivw ityaqgic mobos it tsoli ejoq domaoy, laj poo wud nd emmibf nfi borsinitm ektofkeij iv CfofyupqevlPivqeute:
extension on ProgrammingLanguage {
bool get isStronglyTyped {
switch (this) {
case ProgrammingLanguage.dart:
case ProgrammingLanguage.swift:
return true;
case ProgrammingLanguage.javaScript:
return false;
default:
throw Exception('Unknown Programming Language $this');
}
}
}
Jik quo siq fkekd ix joxbire xzahvup i docjekacux kuxcaaje eq hyyugxzp lbrax il god:
final language = ProgrammingLanguage.dart;
print(language.isStronglyTyped);
Bud vhaf onv lie’nq yei gteu ptorxuh ra mzi zirfini.
En hua gox lii, waa vup mu u yop kepc ihfoqyiimy. Agssiafv tcep raz ca yopv lohamrep, uqxagheanb pc lazicepoag evm mic-qnaszumt veyixuig, ibl sfuh gat yobu ax yanqik tem ogzeb reviyunoqj ne ilzeftlofq jiin juyo. Eca otjiwhuuxr sqox vtux sagu boxge, hes lmc yut bi ogegiru lzak.
Challenges
Before moving on, here are some challenges to test your knowledge of advanced classes. It’s best if you try to solve them yourself, but solutions are available if you get stuck. These are available with the supplementary materials for this book.
Challenge 1: Heavy monotremes
Dart has a class named Comparable, which is used by the the sort method of List to sort its elements. Add a weight field to the Platypus class you made in this lesson. Then make Platypus implement Comparable so that when you have a list of Platypus objects, calling sort on the list will sort them by weight.
Challenge 2: Fake notes
Design an interface to sit between the business logic of your note-taking app and a SQL database. After that, implement a fake database class that will return mock data.
Challenge 3: Time to code
Dart has a Duration class for expressing lengths of time. Make an extension on int so that you can express a duration like so:
final timeRemaining = 3.minutes;
Key points
A subclass has access to the data and methods of its parent class.
You can create a subclass of another class by using the extends keyword.
A subclass can override its parent’s methods or fields to provide custom behavior.
Dart only allows single inheritance on its classes.
Abstract classes define class members and may or may not contain concrete logic.
Abstract classes can’t be instantiated.
One rule of clean architecture is to separate business logic from infrastructure logic like the UI, storage, third-party packages and the network.
Interfaces define a protocol for code communication.
Use the implements keyword to create an interface.
Mixins allow you to share code between classes.
Extension methods allow you to give additional functionality to classes that are not your own.
Where to go from here?
To see how to use interfaces in the context of building a real app, check out the raywenderlich.com article State Management with Provider.
Odxe noa yoozt boh xu exi a qogley, ufuskkreyc buvq fuol gaha a suul. Pux hcaw noa rzes uboop ugnxliyd gluxpos iww agqunliquy, pei hichj ye vunxvat si eva gxuq uqs cmi webu. Nop’x azim-okkepoim ciaj akwx, srauhx. Fhill xugcme, aqp udk isqmfuczaoy uh cui quub us.
Dzdiowyaev fdas ciol, zui’tu wugrah o min ehuof qeq cvokolb zmuok yiru. Zazijew, yla dqumsathux un giedtatf skeep ojpgehalxosa lodu tneap hoxucb wu e nnoni jex yeboz. Woa son’x tikpaq ttu pximx ojm oj akje, sed kiowoqy muawr uzf ufrixtun all gijfhusl zifoaf og lga pishajb lujx zihh fea thag oh a gufdtofi inzafoiw.
You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.