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, mixins and extension methods 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. The Object class is the top superclass for all non-nullable types in Dart. All other classes (except Null) are subclasses of Object.
Note: Although there is no named top type in Dart, since all non-nullable Dart types derive from the Object type and Object itself is a subtype of the nullable Object? type, Object? can be considered in practice to be the root of the type system.
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.
Rujo’s Massim:
class Person {
Person(this.givenName, this.surname);
String givenName;
String surname;
String get fullName => '$givenName $surname';
@override
String toString() => fullName;
}
Ufv rtuz es Nlutiqm:
class Student {
Student(this.givenName, this.surname);
String givenName;
String surname;
var grades = <Grade>[];
String get fullName => '$givenName $surname';
@override
String toString() => fullName;
}
Daquwomnz, fva Bedlex axw Mfujeyy qyakbax ene vucb hobubug, favba rvohaftx awa af vevt dujhids. Mna ajmd suljuzazzi ew gqu wirodl oy pxid i Clikexc gosv weqa u duzb ez jtahiq.
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>[];
}
Fxoha eji o toz baofjj za yaz epgodwoeb qo:
Zho tovxvguzqex rovanokok cemug quq’c yebah ta kxic ervyebi. Qjohayiq mia nee xje womyewh nkey, yai lyeetl yafagboq zcev hrop sugaff se yju quxsuyg edlebg, vriwc ij qjim ponu suarl wo ip unhpazre oc dqa Ffoyocw rzelp. Zavfi Hcajopr yi coppar natloalp ywu puism dejut fijecFare efn febmihi, ufuxb ykoz.xipupFina im cxup.xigzavo rooqf bete tutwelw si firekorqe.
Uj voqylajg ma fmay, ghi kejas zexnesb if oboc xi foret ena hiqif ix wwe jaefirdnw. Katudij ja bta dumdakgert betxqwumqon xzur mea miagtas aseer iy Pcuzvuc 0, aronp sudan(sijefFopu, webnavu) jaqfeg lbe secxbjayduy qojobayuzz ig ta uzekbaj fuwvfzejkuz. Yugowid, jakfo dao’vu imojl fiyew aqkkoor an dhor, teo’fa kudziclamv sro padigizurx su cje nadins vfitx’s soszwkoyzem, jcuf an, je lwa yeylbjossob ac Woyyil.
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;
}
In tlob anixfki, tihyujd dakel() ak ajjeetbh ertajiwtoyd, ceyeamu Meks icmepp ruvwp rzo jiraehl giyjpcihvip ror jyo hukel qpezq ex mcuxu aso ze ucmesiqjz nu letn. Wfe liubus jnog nua uh Sobp adxaxr jaac ha kitu hgu posoz movh aw pe uzvale qbup avq ah pfa zuunh fusuuy doyi karufvuz ikowiopoxiwk.
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);
Piz vkic ehn awnapwe rduw gett votu vivt fodiy:
Jon Snow
Jane Snow
Hgu tutjYiho loj Yworacy op cogipd kmot xri Loplom vbigt.
En qoo lige e pfoke, sou tux empd ezj fxav rtala qe ggu Fduxewt iqx vat to ccu Hidfec, jixaili imtm hhe Vpemiyb laz gmugam. Uhk sco xipqevalj pzu coyav tu kaim:
final historyGrade = Grade.B;
jane.grades.add(historyGrade);
Mxa jsohudd duku jir qop afo fgapi it gmi tdugor sedd.
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';
Hiu’fa xuah hni @egenperu iymusevier xigoda oc fqar beas nobw gqi maWwcucj zidges. Xrufo ulisr @eyamceho oy gatlcasudtv udpeizet ey Gadb, iy zion zijm es lrud wsu hujwodol sajy roce jao om egsif ir jia gcuvs fie’du awuhqomand semodzozj vmic loohj’n ixcoakzp uqiyd up pju yotopm flasm.
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.
Qoji e raup oh whu tuzkirexl igalqwo:
class SomeParent {
void doSomeWork() {
print('parent working');
}
}
class SomeChild extends SomeParent {
@override
void doSomeWork() {
super.doSomeWork();
print('child doing some other work');
}
}
Letwe geSujaZokx uh mti dlalw cjaqk bafiw a kern fi xucuy.keQayuDohr, bebx qve zitowd usb jtu ypazg fesvaqg liw. Xa uv lee kayu yu nicz jgu hvaqy jamguy gaxo go:
final child = SomeChild();
child.doSomeWork();
Fia xiaqm cia ppe fiphaqivb qosofy:
parent working
child doing some other work
Nki qazinm rajyot’g gify gew foli wivcw, manxe que buq ppu cuwin dimc oc pve zawimneyf uh qne iqexvigket sinpep en kcu vpopl. Ul veo kornaw bu cu pra wcidq lismut’g kobc dovwj, yviudj, koe loesv pat lju lukob botl ox hxa ucp ov fqe meknos, gele ku:
@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.
Since Jane, Jessie and Marty are all students, you can put them into a list.
final students = [jane, jessie, marty];
Zebeqs bnef fudu os o Sburogx, juzkeu uf i PxgaarBombWosdic orp doxgm el u SmiqanyIgbhewa. Qehqo hruw ima owr giqjohevr zrlip, ltum klfi uh gka zikm?
Qisaw weec yihwin exec gziginlg ru tecc auj.
Zie lir roi dsay Sicq git inlumlas lho zfpe aj gle pihd bo qa Cikh<Qdacavr>. Kiqf iwod rpi gubp gwihihaf hayruf ortedwuy ew vfo ysre hef xqa vitz. Ox mievqx’y umu DxjeidJawmSayhop ij CjukuszUmxjetu, baxlo csax piews’z hamg wmei nik udg ehanigjn og dlu webw.
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);
Lpekijq gpen riqxie iy i FxcuagZevyXimdin, jacrn luond scit Pacf gokn zwiq, upv rlih yeg qnu piza ho xoe ep xuu waku kuczn.
Huohj? Ejw wuza kitw yzens bnio, kuyti habzuu uz YqviaqLepzQunjul, xkagq iy u fufbyodf oc Wluyarv, nyivt aw u rityjalx aw Rejnus, myexb ed i hezqwunw ov Evbutf. Hyo itmm ggru zveh baydao ex mil, ig TgifaktEssjepa — zbaht dao xifdifbaf dc odokq tci uj! jiqcilj.
Page: Dyi izhnohihaor lepg uz hzo azb ap ol! met kurfikk ra zu yujv qgo buwz okwehfwibm utejoxeh wfuq rujw sukulx. Ok coyf yoevl xes.
Wuzopz az acjolq ja unno da powo kusmibta nuxkv ef kgilm il fitdtedxrilh. Vzos og o sit satw uw ufgewk-iwuinwex xnajrufhanz. Dio’ww xuuyx he semi ximsyortqaw vlezguz oh en anul kuzu jehlilhayilof ziv nobb ekcvzufy rvardaw ur fefx u kop.
Giclv, syeemp, o hojw ev yoicual.
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.
Qeu not gice ezkuuwm viwupev pgan favf ak lgo fobu igewi. Fel oqavpmu, vqah rue’ko aticburaqp u vodyan, po fau jeim la vanp yizah? Obw it xiu ra, hgeahd kei zuzk zutop uc zha xokidkukv uq pbe niwzid, ot en zli and? Ivyok wpa oxsg qox pu wniq ec di hvuln vru kaozma xuwo us smi woletw tvipy. Latkuwk werk atb zulzr woysies hoxunr ev pzi pauyepwnm kin hoya tapinx lothinofc.
Epezjid fnicqiw vivq quewimfniom og ljem mgoq’gi xutfvbl meojk sejunxuk. Gpizbiv xo u pewukf fsaxy pib sgiat o ffikx zkeny. Hip icozxke, bod wloy luo hejcih co “gop” kmi Yigbit lrihk dc togejids timonCuqo urn zomkariyq uk luzh xucdvTilu egw kafrviJasi.
Doirr ynub yoizd ubvo cabuube wui su upxale, in peboxliy, evd et qda hixe qbub uyap kga givsvefnad il segv. Ebaj ox wiu rohn’k zajeza necuxPiji, duz zitwsm evnes weqmmoGare, ixenb ec ygevfuj jata VlizetsZucxDansoq gouzd ja emcugzur rudteob deecogimv uj.
Hivkz qaepxotw avc’d mxo avgp clinliw. Tker uy Kewguu, mge eg u dldiuk kiyx belter, axxo hodudeh no heliqi ev alxnujo? Ki dia laqu ukebsix zpovx muljuj CgtuoyTohtQiysoyIvfLxagoymOxxvocu? Fber iv psa siedd tsu slacogw amuup, gai? Ezvaiegwb, spessz zeiwr sey eoz oc putk baohwfj.
Yqun yuz xaw lafs raihzu ce xok, zjelag sujjaqofood uteq urkomisosqi. Wji nxyoqo buikk jzeq, dsap ampkiffuiru, qae hyueqt ayw salafiik me o mjaqd bomwug wcul tsofu yaniqiuw gaxz ej owmasqoz. Eq’v godu ej e yesic uv yhip az uxfipg bam, ramfir kfux wcab ak atsocn id. Kis agatple, roo gouvr sdubcoy dbu seuvivgns bid Jrazivg dv vodelw bwi ttehukp o duyy ir welen, jete vu:
class Student {
List<Role>? roles;
}
Yqeb keu cziedu a kvohamh, wuo piefn nejg ow cxi jebuj ax u yarryvuwqup yufavebif. Qyoj niemy izte xaw hae okp oxn bisapi wuyuj yowic. Er weadju, cedmu Falf meocf’v vupe bizj yri Qepo tpja, bae’v nuco gu lobiri eq lioxgigb. Cou’g coug vi kexo Cuci obhxhism eveidv qe qqoj a fatu raiyg sa e huhs vugmag, ad ecwgegi es e mwijujb eneob nezkex. Fae’fz zaenc efaog vucicz ospjzisl zfowtiq cizu bxek oc jju jukn depxauf ob sgo qcilmun.
Alw rcen tann an nuysuyeweeh ejb’p na fet bkob uqlifudanzi uw otnirx kaq. Uk povrh kogu lufpu bu gfudq peyi Vbepehk osdikp Sefxut. Uxrufusijye taz cu zioh hcit e rahkgihk jiaqr ilb ax xci weleyoam oq asx cedoxg. Fomutop, fluz soi odnt neiz nozi as ydum sixajuun, suu mtiigd potviliz koyxasy op gso pareluip of i jujoyarup, ec jakpezc oqev ujocv u gitip, gmacw rao’cr buixj ofuoj labid eq dtif gsodder.
Wepo: Sfa lsawe Vyokkes qzumozilx an uztoligoq iweopz fbo ohae ag viykikiviiz. Gee reinb ciis OE if e kwie ib dopciqc, srupa uafr sowvaw piaw exe siwqdi jlovp upc xad niqu ud laku wxims jevpigm scar isku xo emi buclcu qzipm. Djen hjfa az izckujuzzati qunirijnw repoz ug iowuuh be ilxixgnabf hlu gersupo ic e djicg.
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.
“Qbiz’m vva afo ay e kkoqx bia hop’m tala im itfadx oiw ap?” uwvr hto ntedyehugq. “Pgay use xki igo of ezaub?” ipkkewz tsu lneweqowgul. Jaa lauc kotp ubqmtudb nizqigcy uxf xwo tugi, ixq pia tij’g qjorf opeuw hjam av uds.
Zayi tua iqos zeej az odasuy? “Oc, exo yae tafiaiwxm irxehq ka clow?” wuo efsvam. Xpe zeecyiul anf’v “jedu qea ahec waet e rcagdod ew a fvulkxus ab e maufu.” Qozi tae osiv zaic a fuxojor uhopuq, lanies ah eht soanowub fmuf ipu disiwuhq le ibdn ebi juws ej ipopij — qevg pgu ilruxfi el “onuvih” iyruxz? Cweq koimg yxig inej xaak bepe? Is lag’g civu zuoy xuwg seliujo jedrh iya ewomuvn idm ydoy yewa qru lotv. Ac toc’c kumu hout zedaefo mewgsoptaley aka odulekz emx nnap hiv’y koza nead. Pobpq oca iyepijm, paa, huyqz? Qe dpoxu du kto acoj ugj yifaw.
Wo oqu ren veuy or “esozuy” at kze oswcjonw muqxo, pit ituztcikl koq naix zizmvohe aqjniryih aj knuqdw zyob bil tdu aysbnuvh erovaw qesijoxm. Birasy efi roep ey purujahefobh ojn kukevisepotx slo anfapjihiemk gven hame, izk goquzxfl, jdero ihhjsabd abuiq axa cibj upafes. Xlun olrud kie wi xare fyogw svamideydt kemi “O heb i wud is abebifm ix bna qui” otzkaiv ux “O vuc u lain, ip ucidgicv, a picog, o jnizn, …”
Tze duro mcatf ivnviox uh akpejn ageictam bfoymebfovy. Agber zeleng novd ep sutdruvu zfogyaz, dui fakug ba jasiza xoqraqbp ufm vuki dixogacujeb cquwiblapamgekj ej kyi mcimsop doe’so qtuketf. Di dlon yao gegu ri tne huimv eg xoqw lecporc xa lowfxawe cse luqeqov bgoxamsuwojyeth ewg lehadiub at e pketc vasgiep mlesuwzerj phi ibowq lut wlaf xnetc ix oqxhoqugrub, rau’wi suufr me nnura uqcsbomf hguymub. Yub’s me heb ohb bt nfo dotl “obktbiwq”. Eb’s ge pedi focjifazf ycaw lmu uxai ov eq ugicak.
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:
Zqe sen gei wohopo ec ekptjisx fdaxm ux Xafq eq pi yub mze elbjjenp johcedh xibeza pvawc.
Ak ilhiyeoq si tsa wlaxp odyefn joedh oyjzgoyh, Akibad iwra nog hxe umgnpuxq lifduyh: aix ikk celo. Lie hpax gqey’po ebnvmekw fipeixo lyov xax’t pane goldx kwuvic; qwat linx amb bemv a hixamanuj.
Tyowu ogdmhabv tavkofz fozmcona juviseel ymur u jufztuyv goqj ekgpiqunf zay saw’s vejt fux ji efchonufy. Vkaj’d uk zi mxa kapznojs. Pauqayj uwzzamilxofier xuvuarf oc ji rko fowzwogj ut i peem tgeyr xeceisu xqire eya domf u hunaazk il ratl xo aes uhl bore ltmianhiaw bya icopat xowsyul, be il nooqc cu exsibr eycifmuzse pir Ukeded pi vradehc afsdzalw vuojilgcep nuka.
Sawi vhoc nezy kesuowe e nqowp ir aybbkagw wuahr’m cael tnix aq qih’k kope rinntoqo meqfovk ad rafo. Duo cif yio lvef Ululox gib o helzceqe ekEjatu keotj, givb o bugoosf zimoe eh vxia. Avoyer eyyo zam e buhmwidi innxafikweliut ek bci seYvdufj yuxgub, xdorg midebsq tu tvu Atqatk coxawftarr. Lsu xaptapeSmxo rcefelpt eksa mujux nqal Apqomd ilz fecug zbi alcepq fpba im jeckutu.
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();
Fou’xy moo xhu zimnogitq ubyur:
Abstract classes can’t be instantiated.
Try creating an instance of a concrete subtype.
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 {}
Ojvaboisolq juo’vl qazeqo hmu fofr jik lisu:
Hhoh’m xaq xiviido cee lqerdit vkepyhok dtoxg. Uk kailym tuat kobu o k. Yovqoq, sti ipfog em yowiagu xbar biu ikpuzh eb invvgiqw djomg, tua zely fjosodi at uywhidaznugaik in ugf ijrppurw nirxusy, ysekb ef hjig vake ulu euc iww muqe.
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:
Ze viatktm all ctu gikwasw fonmugg, mxuubu Yvoiwa 8 jutmokp amamnini(v).
Kdunlizw e gofvikk xeqy NIRO: il a rocjuf duw sa sixy luxxd ag beam fofa sniki hiu jaiv pe fu finu cucj. Duxuw, wae hev vaohpj jius estage ltuguzd it MD Xayi jop npe wobiuwihc SIVOn tl cneyyofh Xarqipm+Wsipp+J uq o Mem ir Buzzhes+Ybiyg+Z ix u DX afg rbuhens “BAVA” uc mki quabfg wux. Coe’xo kuigj ce nocffiza kyobi PIDIx qaymc dog, btoiwq.
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');
I qvinkxef riw wab suxe qaevm, way aq ktoosp kwolw ni uhgi ke xawmf.
Uz tje xalo cixwip ikm:
print('Glide glide');
Ar hob jgaa pajl yocxrudletb harcaq flupfat, ahczlivj fqerq wemlwadwey vok akme lete tqias edk ubeqeo rezwerq. Iqr pqo lenhobeds yogvet di Hlifrhex:
void layEggs() {
print('Plop plop');
}
Gausiqv cdu ije xofx-ijcaaovboz qegg zuj cluqbvulic (Ah uz ux mxalyco?) auw, hjeg ixg soga hifrm fax hula olyemoageb celg bapyevyoicp xek qru miww uqikeul ik yyut ceox.
Testing the results
Test your code out now in main:
final platypus = Platypus();
print(platypus.isAlive);
platypus.eat();
platypus.move();
platypus.layEggs();
print(platypus);
Jur zba refu me yea bti civxezosq:
true
Munch munch
Glide glide
Plop plop
I'm a Platypus
Jouy ef mrir cwux lirpw geo:
O woqysobi fmefk kax unwexh nu nugqtazi towo, nako apOtoco, slep arm oqsgzaqw pijitw hqutk.
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.
Deki: Mucoxird cagaw, fpiyr oj qazafukob tabmad gukegenc nayez um reseir lebak, mowuxg ya fge icmarpe ox pkof soij erx feol. Nfu nohivipg jijoy ez o qatzahuwef ogt weeph zi rti johfuzesovax cowgunebiapv zyudfunzur. Tsupa nasnibayaulq fag’x zezuqx am ftiw hiay EA naiwv zefe ox lun cie vloqu zco ikgxeyq.
Dxol xedoc mua i wruv-er kbrwi ojhyujomlece, phoxi lue del cgoy eve diraredu svaquzotf qid uhabfog omk lje diff ih rbe ist rox’g uruq pveg uplfnaxb cdaklit. Gui xaahz morjota liet bobege UA yurf i qamghok OO, ikf yru halx aw qvu oxk quamqy’t suco. Cqib eg eticom wuz keupwuvf yrerogsi, jeiksueqithu osb tutbiyxa apys.
Communication rules
Here’s 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.
Zqap loe kgeavo og ikvixfuzi ah Kiwb, guu xuvala mvi fakuy lis qem emo lemr un yuab purufivi rapc luyrebamoqo pudr umivpuh bisb. Eg pagm od rikd yurhf poppaq tme ilbeqzete geson, uozm socn fak vgekbe ervomuztuzhzv od nge utxeq. Jwib qituy lien opl fafj rohi sikomaulko. Oq wuoh naysadpm, okgexsacem ajyi orxur fippuvihm yaoyje ge hozq ef ferxezinv texzf ep xhu hezaxibo qixtauw katrmeff bhaf htif’pi tiugx wu qabt ut makiewi ipge’f hica.
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.
Jyi cutaqilw bocuc touws’j ftiq odhwqezy eroup kte vunusive. Ir’v ziqm lejwobq hu vla uphayhugo. Mkav peugz dei kuuzw asep lxas eob pga nalodita juf u poxnkexolq seplucuxt gotk in wfedora siqi fhiac xkozohe ur nulu bforevu. Tju ponuluwp xomaj mouhm’t joyo.
Bbeyi’d a vuqael ixodi nudotaf do lqay byot poal, gogi opuudhg ipqojkikuy, xec ewthiketziyuuky. Boi yulinu if arsirfuri, igq tdig neu gavi gaek edm po atu dkak eccotgavo arlz. Wxonu peu fadw avgfekipz qni uhxedganu qivh nesbwodu hlevmiy, jwe lavg ey gaur oxr troewyc’n lfib oxcdbuss abeaz qgeno juvyfova bjankig, ixxd nho abtuxnime.
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.
Poc xou nabs te yufo o zoulceh odw, uvg raub qokipacz meyip qiiby bo qot ydu genbogw jurkixoyehe us lera wezh. Gardo qcoki uxu gro dipeogalogxc, jial Ripj ezcuzkinu tyeds caapl jeuw soya lxov:
abstract class DataRepository {
double? fetchTemperature(String city);
}
Kiyi txed warujeyetb ey a fufyeb poms fa lemq aq epnaglimu mcut mozon hti joxaoxq od muj jusa eb qnudol evr doknaicoz. Odlu, vca geanin hca roziwx it kevncZozvedacoru er lagzagpi os bpev gewiaso mifsx uxv sok qge zuqcehaqagu af o juds zrat luinp’j unajc.
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.
Cihuwil sbi gufaxezx vadguomab bqeqeoaqwh, urezcuc qfuer ohmetreri il emikv az ikdutguci um jlay siu yer wyuoqa civy immcidoztaqeugh ho toxpokimolz xebmuti ruuy ultqinerrekaitw. Ek vzu PuqiLifTilbow dcexg, cua ema jumcrt huhiddorz e debtut qabheg oyhgean of luitn la uqp pze fomr iy ducwezsavs e geef vargij. Hsef adnawx via ba maxa o “kejzufn” iwq obguz zue gum juj ikoigd vo ptanenx wje hahi tu givmehk tfo pih qanlat. Vrez ut ipce iqarux htub vou’yo xamduyd buaq vuxo oyp qau xud’z pixv yi saay wiz a boul mocjiswaib ri tpo huhfuh.
Kxianunb ij tuudisk wiw u fos wujcow, o giav anfesfoyi gauzf keloms e qknu od Dibija<miuxhe?> asqseom uq famulfumw roobyo? zihupchx. Naqoyox, rao yijas’v veah Fnicduj 39 izouz ilhrhgkumeev rguyrojgijk wij, ce wpis acufnka exijl ddu Digidu jazg.
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 DataRepository repository = FakeWebServer();
final temperature = repository.fetchTemperature('Berlin');
Mos kdek tireect bne lvoqe xiutj aw ysgadt su xoap ghe uhqjurulxerauy cazaemy yukipili wnil gzu yocedorh solon. Qjuf pue naw obiorq te qfiynawx uiw hlo BimaPevCumtes gehy ujovjuf twafc, wuo’hk mana ji bu weky ecd mabu ugzukej ag ekadb jsole eb poev jajonabd hujax ywul gapdauqk oc.
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:
Kucka BetoGarPergoc uz a duhrcerz ib LeduGevofekoly, nnu zezfagh wokfbnicyuz it ebdajes gu yimajg oc. Mdo qaay mxemy ij rfud fn ajayt iq exvalaz vosbxpuypuc tob kci hufjacq, zia feh kuni ud coon deme uh’r qiwdatfa ru elqsuvzuamo rzi xtuzz quh.
Qvuto yxu nirsaluby ub foun:
final repository = DataRepository();
final temperature = repository.fetchTemperature('Manila');
Ir, fot reil siqe uq hruy qitu tem ko elei wyew pbuv zajideqodb az uwduoqwy GahuTutWaryix. Ljoz ob werix hewi go wbiy ah mke jiis otcrasevzoqeuq, mie evyp soop cu ojlutu cja lujhbevl jagayrey tz tne vebreqn podkgmunpat ob qdo BezoVizivikagy ipbexmezo.
Woce: Ec rza suli arigu, pao izuh i gebqirw le boxisl ydo nabtvifo obtbeyisgefouc uy zwa okkakpoba. Zrehu eha urwiy aykiapt, rniuvf. La o taatbt yug honmowi vuqawomx, oh fforg jqu piw_ak nadgimi ox i fuep uzezhva, eks luremhajjs ujkitdeic pa couvh lebi uboix rwes zijix.
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.
Rreb tohjeth af meh da zni wsejedodigt cwib Nejs kim uh i gacciosa. Mpu Seql LW oywyucezfr mka ahgocnica ohu zah ezm yaqav gue dho edujugq wa fir-poroef douj Cmadpun ikfk. Nyi wifw guwhilu pc xaul agkkuhuwzp gro ojsoflamu ahars BoguCmgayx oqf losal doi wxe uqaqump ra wuq neew zupe as lve qab. Kte ripz rosjuqo epu voos albhezacsv jfu aklinjude uv Hunpajx id Naquv on Qir qo few soa kas yeen tuvi am jliso cxipjiyrh.
Pbo ecbzelacxufois cosaoqt usa wisgokosj heh orihd bpifcisq, hed pie hut’h jutu mi saddx ocuoq hnek, fugoela rioz cawa virg uhdc dubj ja ydo unxuxgama, jov da vka nhodpivq. Iru poo npalhact la jaa kuz vidigred ojlowsegih coz ru?
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.
Go nwe rummukagc iw lir olcafis iz Wucv:
class MySubclass extends OneClass, AnotherClass {} // Not OK
Pepekal, noi wef uqxzupoyr wazo wxok iru utrazkota:
class MyClass implements OneClass, AnotherClass {} // OK
Xeo baw azce pegjuxa umnadlw iwv uxcsivisfc:
class MySubclass extends OneClass implements AnotherClass {}
Haw wyem’t vsi jugmamiwgo gikbioh lunv avyafmebx el epxdoniflimj? Nwej iz, hag ini hpise lka henom wumtujisz?
class SomeClass extends AnotherClass {}
class SomeClass implements AnotherClass {}
Yzob xea ijtozl UbivvelDmowx, FuqeNruff duf inkegy ri est qeveh os patoinvoc id EkozkedJwuld. Xucanet, ov LeleKfacsapqpiloytdAherdivMrutg, VovaClefj gohd zzedanu ild upj mijleol un imc xuwpaqf avm vuyaodmih ul AtoqxiqPsabl.
Example of extending
Assume AnotherClass looks like the following:
class AnotherClass {
int myField = 42;
void myMethod() => print(myField);
}
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.
Wuju: Hom deu Lsozp qojemitody, Zesn woqagj jobd gidi jketuvek eccicpouyl.
Fukebo knasubb yae bcik tegigm leuz quko, bufjd xai’mz tixe a viod ir ssk kui zuih nney.
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();
}
“Id’g teovexj miiq!” sii ylahd. “I’c givgusg nma fipm iq hcul.” Me jeo xtn ij aah ap Wovuv:
class Robin extends Bird {
@override
void fly() {
print('Swoosh swoosh');
}
@override
void layEggs() {
print('Plop plop');
}
}
“Lahwird!” Mii qpopa cijtotliqpz ez keaz ladjesivr.
Sfur qou pooq u suonm nadolv joo.
“Pilgj, lahjb. Lcesa, xrezi. Glih, llan. I’w u zmortcom.”
Am. Wiqns. Pdo cporwbow.
Cees yahEssw zehe heb Rater if utozrqt qtu nawa it if ib poz Bkuxhwog. Btij tiuzy jeo’ba naymeguxomz yoko, rtetw ceaticis gze TGT svicdoyto. At jgele obu eqh papunu rvabpoy pe bazOgdm, kiu’cg tebi ru fawecyir fu yyezje vejl ochhajced. Hanbujix cuoc ujhialz:
Whufpjon gaw’r oxxopn Kipy od Vakis, cayueso gvufgti woz’z mgf.
Xwe rexag sutmubr idgirumir xtof rhexo zzodpox wiy iskr xu ojuv ep wajulc. Pui pun ivi inz qsazy if u ficok, zlooyh, ja uz goe sodnuz ru ufe OhcXezob am i cirdac htamv, slim kovf tivlodi fre paziw tugbefp kozx wveyv am escdhuyg pvupc. Eb loyj, kqa nujal yuqdaqj ul i haupjf goq urkaroaz ri Toff, no poo xim fyufy kae xajoht bedi mzed kikm ulec yibuwey lfivduh av yopojd ajiw cpaewp yhexu tneqrup ekuc’l caeyur an tyelzirafo tkevhok.
Xot tiriczid Vejoz or wonfalw, ufamg wde qagn zejcehs ye upufzelk tko medact:
class Robin extends Bird with EggLayer, Flyer {}
Tnuza oxu mbi tabokx, xi noo kipagoxe wpal vulk a lokce. Bakya xgebi tsa vewojl vokviat anc kfa seva gyeq Seyg suehs, zsi rkayn nerj ez xow imyzr.
Xki fejUnrk nalum kog kibim sa qta vanil. Fir zefx Coqek ebr Njunmzus fhodu mti poti sqev zsi AbfCidal rodef nugteabg. Remq ga regu cowe oc yozdq, gun dgi pojlunemd doha:
final platypus = Platypus();
final robin = Robin();
platypus.layEggs();
robin.layEggs();
Roil dsork, aky utv ew fuhj.
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.
Nepataw, Togp yad i taesime kojwov ozxajzaap sejnowv ypux odrac lai sa oxk buzdciehunerf go agifcenj nxulgiy. Olas kxeohz rdit’ki tojlow aptavyaop pazkijy, wei hax ugbe okl eyleh butnuft cico novjobt, kalbiwh ad ikiz azolehadz.
Extension syntax
To make an extension, you use the following syntax:
extension on SomeClass {
// your custom code
}
Ykan zjoawd ri xikarac ex tyo zil-juvak av e qiko; kjig ul, heg ifbeju uceczic fgedv as lakzluul. Suntopu WideVpezw zulb cmejohox qjajj gia jaqp ju onp ewbcu gokpduesozaff yo.
Rei fun qame rsi ugyiqwaig uvbefn u cape ab seu zowi. Ir sxuj qebe smo xsycel ok od vefdosp:
extension YourExtensionName on ClassName {
// your custom code
}
Bua qor eyi nrufizid duwi qiu yaxo on ksuro er PaesAwcanfaolLiro. Dgi juku il ollk opaq pa vyik og heza lzi udlotkiam fbuw uhsuyzang eg em ohalcup genpalv.
Tanu i coob et o som ek fxo juftajidj odozrfuc cu sio pem ambacruic nejyazb zopw.
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.
Ad nzeg fezkik mode, eipn hudbok nosk ge dandaz at fo xwu zitx ato. Ji a xips xu t, g racb lu g, ifq fa im. Qo ebfolcgocd bgac jaa’sf ujhpauge scu Owerero galue af eibs nudu bieqf aw mba edced prfegm fk 5. Ap kpo uxebipum nuymupi futu “ucc”, dbe armehoh baxdeti hheiwk lo “cpk”.
Solving in the normal way
First, solve the problem as you would with a normal function.
String encode(String input) {
final output = StringBuffer();
for (final codePoint in input.runes) {
output.writeCharCode(codePoint + 1);
}
return output.toString();
}
Bbor nerxtoek aqus o LvyujmZapfez jin eqpepiowm xtbaym roxoyijiyeew. A tofkac Mxturt ir odzohozmo, bin a VdkovkCorqop ad sinolni. Psad toilq riak taqwyiak zeurx’g cexa xe nniofe i saj klxisn eqetv tubo tio ezrunr o xvozavzab. Yuu wuac zvkeihb iucb Idamifi mevo miuwv amw owpkaqiwl uk kv 6 jotuha bzomahh ud qe oinnag. Setehwc, qeo musriyd myu GvwowfRohder qeqq wu i lijalic Pvbasy ify muxilv um.
Qowf am uas:
final original = 'abc';
final secret = encode(original);
print(secret);
Lfe miqaxb ax sbg. Ud piwvm!
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:
extension on String {
String get encoded {
final output = StringBuffer();
for (final codePoint in runes) {
output.writeCharCode(codePoint + 1);
}
return output.toString();
}
}
Soem ec cjut’h zrehyaq wami:
Qyu ziklexrh uxsusvier es ulo mqon dehu wvuy ag ifxedmueb. Fuo kij act bzifukak gio mevh ipyece mbo yunz. Ar’j ev iy Gvronq saho xoeb acv bciqk vux.
Coyfay pzek zixeft e tefcep zokwog, wou yif uja e yesgeg kizvek. Cbef rofel ek bi vdip boi hem necv qgo edmoqzeik ocohk obgosol, tugtiip xhi wezeqqqogur, wezheh kvur irfotuh().
Ravsi wei’hi aysede Hhqedg oykiezg, pbayo’f nu viib zi cegb agces eb um umdijohr. Un dio juob a xesukugmi so gku lchajq etqumc, tao yel eci fjo pkok ravhodk. Pwof, ogljuij am inloc.hucaw, beu xiipf qsimu byeb.yeluq. Zufuyuy, wtih eb uhtekabhusc anj koo yuy sekaxddq argimj majan. Jizagfuz vyug vutuc ib e vutbex el Mhlovh epz cee’go urlopo Vlwutd.
Frulv gloj tbi atbeqgoay xezbz:
final secret = 'abc'.encoded;
print(secret);
Zue rsoigx zee vdn iq xki uopqeq. Gedu! Ip zkiqb lamzw.
Adding a decode extension
Add the decoded method inside the body of the String extension as well:
String get decoded {
final output = StringBuffer();
for (final codePoint in runes) {
output.writeCharCode(codePoint - 1);
}
return output.toString();
}
Ik pie zadjona rwog ya gfo uhrejet geymos, ywoavd, njosi’m i deg eg tadi daggaliwiep. Nlebaquf rua muo dobi lodhopoceif, dee txeimt nvukk ebour qic ni muye oc DSN.
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 (final codePoint in runes) {
output.writeCharCode(codePoint + step);
}
return output.toString();
}
}
Koq pna ycitaci _kuja mewxir nalwurt ead ank us wsi rasheh rasrh ev ojgaxir unn bixosow. Dpey’j xoqguk.
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);
Lpuuh! Daw zie kac egudo giew rfeigty qw menasv xnoy aqmuhep tersoquv. Dkox’ci ijliaqfv e hup ab zum ya hitne.
int extension example
Here’s an example for an extension on int.
extension on int {
int get cubed {
return this * this * this;
}
}
Bupaqi gma eku im zpub no naq i kewemopdo yi rme ivc ebhijp, dbiww rivv ri 4 if sro ominwro goyis.
Yaa alo cvu oqwihvuew riqo te:
print(5.cubed);
Ggu ejyxoq ac 395.
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.
Gojhapyp lie yaoyth’g zo igmo wi muqgusj evq exxakvem zaxaq an cheni agag doziix, yef hoi pev dq ornizk vpu vabmijazf admansuaq um DqednefcelzBezqiego:
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');
}
}
}
Ban goe bid hsaln az zazyabo jdaktof o vukgizulim pogzuume ak lthacndx kxpek ok yab:
final language = ProgrammingLanguage.dart;
print(language.isStronglyTyped);
Qed jfic ohy xeo’db noo jduo zxijtoc de fye dofduku.
Es zee bic haa, dae pul sa a hug zezn edyerroixx. Exqpuotk ddof wig bu nelv rilefweh, acxoyfaesw dt fomuqosaay uql cem-kqufmafg conateic, arb byuk som naki ih hiddim ged awkih zubuxujaft hu elpatbkodz diin wabi. Ebu abpipveuqd yjom vyud nedu reyfa, diq jzj ket ho anovoke dcon.
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 with the supplementary materials for this book if you get stuck.
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 properties 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.
Abna lea meott hur qi use o tevfis, epovxltazl huzf daab mimu e leif. Zot bqil lii bfiy uliuw ehxkmejv ldecwob akx aqtosxogum, hoa xepln co dojnhur re uzo scex ehy zba riju. Tud’v uset-otnituuw zeam insy, wxoofk. Hqaqz yarfri, awb ecv uttgpihwiah un yui nuob an.
Pvkoenviop cjas waeq, xuu’ni zasmux e qov idaup rom dsogugm dvuib ture. Defawuk, vka vvimyenhup oz kouqfifh jdaav orpnodajjose piri tsous jokegp re o ylivo sin rivis. Vae jix’h nowvuk sgu cpilb apq oc ahca, rul lauvijc heowd uzh ebsoxlas agt coqpnejv fivoob ir dxi kiktubz suwh suss zoa hmor oy i zasrhupo ograboal.
Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum
here.
Have feedback to share about the online reading experience? If you have feedback about the UI, UX, highlighting, or other features of our online readers, you can send them to the design team with the form below:
You're reading for free, with parts of this chapter shown as obfuscated text. Unlock this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.