Programmēšana

Mantojums pret sastāvu: kā izvēlēties

Mantošana un kompozīcija ir divas programmēšanas metodes, kuras izstrādātāji izmanto, lai izveidotu attiecības starp klasēm un objektiem. Tā kā mantojums rada vienu klasi no citas, sastāvs klasi definē kā tās daļu summu.

Mantojot izveidotās klases un objekti ir cieši savienoti jo, mainot vecāku vai superklasi mantojuma attiecībās, var tikt pārkāpts jūsu kods. Klases un objekti, kas izveidoti, izmantojot kompozīciju, ir brīvi sapārotas, kas nozīmē, ka jūs varat vieglāk mainīt komponentus, nesalaužot kodu.

Tā kā brīvi savienots kods piedāvā lielāku elastību, daudzi izstrādātāji ir iemācījušies, ka kompozīcija ir labāka tehnika nekā mantošana, bet patiesība ir sarežģītāka. Programmēšanas rīka izvēle ir līdzīga pareizā virtuves rīka izvēlei: dārzeņu griešanai neizmantosiet sviesta nazi, un tāpat nevajadzētu izvēlēties sastāvu katram programmēšanas scenārijam.

Šajā Java Challenger jūs uzzināsiet atšķirību starp mantojumu un sastāvu un to, kā izlemt, kas ir piemērots jūsu programmai. Pēc tam es jūs iepazīstināšu ar vairākiem svarīgiem, bet izaicinošiem Java mantojuma aspektiem: metodes ignorēšana, super atslēgvārds un tipa liešana. Visbeidzot, jūs pārbaudīsit to, ko esat iemācījies, izmantojot rindas pa rindai, izmantojot mantojuma piemēru, lai noteiktu, kādai jābūt izejai.

Kad Java izmantot mantojumu

Objektorientētā programmēšanā mēs varam izmantot mantojumu, ja zinām, ka starp bērnu un tā vecāku klasi pastāv "ir" attiecības. Daži piemēri būtu:

  • Cilvēks ir cilvēks.
  • Kaķis ir dzīvnieks.
  • Mašīna ir transportlīdzeklis.

Katrā gadījumā bērns vai apakšklase ir a specializējies vecāku vai augstākās klases versija. Mantošana no augstākās klases ir koda atkārtotas izmantošanas piemērs. Lai labāk izprastu šīs attiecības, veltiet laiku, lai izpētītu Automašīna klase, kas pārmanto no Transportlīdzeklis:

 klases transportlīdzeklis {Stīgu zīmols; Stīgu krāsa; dubultā svara; dubultā ātrums; void move () {System.out.println ("Transportlīdzeklis pārvietojas"); }} publiskās klases automašīna pagarina transportlīdzekli {String licensePlateNumber; Stīgu īpašnieks; String bodyStyle; public static void main (String ... mantojuma piemērs) {System.out.println (jauns transportlīdzeklis (). zīmols); System.out.println (jauna automašīna (). Zīmols); jauna automašīna (). pārvietot (); }} 

Apsverot mantojuma izmantošanu, pajautājiet sev, vai apakšklase patiešām ir specializētāka superklases versija. Šajā gadījumā automašīna ir transportlīdzekļa tips, tāpēc mantojuma attiecībām ir jēga.

Kad lietot kompozīciju Java

Objektorientētā programmēšanā mēs varam izmantot kompozīciju gadījumos, kad vienam objektam "ir" (vai tas ir daļa) cits objekts. Daži piemēri būtu:

  • Mašīna ir akumulators (akumulators ir daļa no mašīna).
  • Cilvēks ir sirds (sirds ir daļa no persona).
  • Māja ir viesistaba (viesistaba ir daļa no māja).

Lai labāk izprastu šāda veida attiecības, apsveriet a Māja:

 public class CompositionExample {public static void main (String ... houseComposition) {new House (jauna guļamistaba (), jauna LivingRoom ()); // Māja tagad sastāv no guļamistabas un LivingRoom} statiskās klases mājas {Guļamistabas guļamistaba; LivingRoom livingRoom; Māja (Guļamistabas guļamistaba, LivingRoom livingRoom) {this.bedroom = guļamistaba; this.livingRoom = livingRoom; }} statiskās klases guļamistaba {} statiskās klases LivingRoom {}} 

Šajā gadījumā mēs zinām, ka mājā ir viesistaba un guļamistaba, tāpēc mēs varam to izmantot Guļamistaba un Dzīvojamā istaba objekti a sastāvā Māja

Iegūstiet kodu

Iegūstiet šī Java Challenger piemēru avota kodu. Sekojot piemēriem, jūs varat veikt savus testus.

Mantojums pret sastāvu: divi piemēri

Apsveriet šādu kodu. Vai tas ir labs mantojuma piemērs?

 importēt java.util.HashSet; public class CharacterBadExampleInheritance paplašina HashSet {public static void main (String ... badExampleOfInheritance) {BadExampleInheritance badExampleInheritance = new BadExampleInheritance (); badExampleInheritance.add ("Homer"); badExampleInheritance.forEach (System.out :: println); } 

Šajā gadījumā atbilde ir nē. Bērnu klase pārmanto daudzas metodes, kuras tā nekad neizmantos, kā rezultātā tiek izveidots cieši saistīts kods, kas ir gan mulsinošs, gan grūti uzturams. Ja paskatās uzmanīgi, ir arī skaidrs, ka šis kods neiztur pārbaudi "ir".

Tagad izmēģināsim to pašu piemēru, izmantojot kompozīciju:

 importēt java.util.HashSet; importēt java.util.Set; public class CharacterCompositionExample {static Set set = new HashSet (); public static void main (String ... goodExampleOfComposition) {set.add ("Homer"); set.forEach (System.out :: println); } 

Kompozīcijas izmantošana šim scenārijam ļauj RakstursSastāvsPiemērs klasei izmantot tikai divus no HashSetmetodes, nemantojot tās visas. Tā rezultātā tiek iegūts vienkāršāks, mazāk sasiets kods, kuru būs vieglāk saprast un uzturēt.

Mantojuma piemēri JDK

Java izstrādes komplekts ir pilns ar labiem mantojuma piemēriem:

 klase IndexOutOfBoundsException paplašina RuntimeException {...} class ArrayIndexOutOfBoundsException paplašina IndexOutOfBoundsException {...} klase FileWriter paplašina OutputStreamWriter {...} klase OutputStreamWriter paplašina Writer {...} interfeiss Stream paplašina BaseStream {...} 

Ievērojiet, ka katrā no šiem piemēriem bērnu klase ir specializēta vecāku versija; piemēram, IndexOutOfBoundsException ir RuntimeException.

Metode, kas aizstāj ar Java mantojumu

Mantošana ļauj mums atkārtoti izmantot vienas klases metodes un citus atribūtus jaunā klasē, kas ir ļoti ērti. Bet, lai mantojums tiešām darbotos, mums arī jāspēj mainīt daļu no mantotās uzvedības mūsu jaunajā apakšklasē. Piemēram, mēs varētu vēlēties specializēt skaņu a Kaķis izgatavo:

 klase Dzīvnieks {void emitSound () {System.out.println ("Dzīvnieks izstaroja skaņu"); }} klases kaķis paplašina dzīvnieku {@Override void emitSound () {System.out.println ("Meow"); }} klase Suns pagarina dzīvnieku {} publiskā klase Main {public static void main (String ... doYourBest) {Dzīvnieku kaķis = jauns Kaķis (); // Ņau dzīvnieku suns = jauns suns (); // Dzīvnieks izstaroja skaņu Dzīvnieka dzīvnieks = new Animal (); // Dzīvnieks izstaroja skaņu kaķi.emitSound (); suns.emitSound (); animal.emitSound (); }} 

Šis ir Java mantojuma piemērs ar metožu ignorēšanu. Pirmkārt, mēs pagarināt Dzīvnieks klasē, lai izveidotu jaunu Kaķis klasē. Tālāk mēs ignorēt Dzīvnieks klases emitSound () metode, lai iegūtu konkrēto skaņu Kaķis padara. Kaut arī klases veidu esam deklarējuši kā Dzīvnieks, kad mēs to instancējam kā Kaķis mēs dabūsim kaķa ņaudēšanu.

Metodes prioritāte ir polimorfisms

Jūs, iespējams, atceraties no mana pēdējā ieraksta, ka svarīgākā metode ir polimorfisma vai virtuālās metodes izsaukšanas piemērs.

Vai Java ir vairākkārtējs mantojums?

Atšķirībā no dažām valodām, piemēram, C ++, Java nepieļauj vairāku mantošanu ar klasēm. Ar saskarnēm tomēr varat izmantot vairākus mantojumus. Šajā gadījumā atšķirība starp klasi un saskarni ir tāda, ka saskarnes neuztur stāvokli.

Ja jūs mēģināt vairākkārt mantot, kā man ir zemāk, kods netiks apkopots:

 klase Dzīvnieki {} Zīdītāju klase {} Klase Suns izstiepj Dzīvnieks, Zīdītājs {} 

Risinājums, izmantojot klases, būtu mantojums pa vienam:

 klase Dzīvnieki {} klase Zīdītāji pagarina Dzīvnieki {} klase Suns pagarina Zīdītāji {} 

Vēl viens risinājums ir aizstāt klases ar saskarnēm:

 saskarne Dzīvnieku {} saskarne Zīdītāji {} klase Suņi realizē dzīvnieku, zīdītāju {} 

“Super” izmantošana, lai piekļūtu vecāku klašu metodēm

Ja divas klases ir saistītas ar mantošanu, bērnu klasei jāspēj piekļūt visiem vecāku klases pieejamiem laukiem, metodēm vai konstruktoriem. Java valodā mēs izmantojam rezervēto vārdu super lai nodrošinātu, ka bērnu klase joprojām var piekļūt vecāku ignorētajai metodei:

 public class SuperWordExample {class Character {Character () {System.out.println ("Raksts ir izveidots"); } void move () {System.out.println ("Raksturs staigā ..."); }} klase Moe izplešas Raksturs {Moe () {super (); } void giveBeer () {super.move (); System.out.println ("Dod alu"); }}} 

Šajā piemērā Raksturs ir Moe vecāku klase. Izmantojot super, mēs varam piekļūt Raksturs's pārvietot() metodi, lai dotu Moe alus.

Konstruktoru izmantošana ar mantojumu

Kad viena klase pārņem mantojumu no citas, vispirms pirms apakšklases ielādēšanas vispirms tiks ielādēts superklases konstruktors. Vairumā gadījumu rezervētais vārds super tiks automātiski pievienots konstruktoram. Tomēr, ja augstākās klases konstruktorā ir parametrs, mums būs apzināti jāizsauc super konstruktors, kā parādīts zemāk:

 public class ConstructorSuper {class Character {Character () {System.out.println ("Tika izsaukts superkonstruktors"); }} klase Bārnijs paplašina rakstzīmi {// Nav nepieciešams deklarēt konstruktoru vai izsaukt superkonstruktoru // JVM gribas uz to}} 

Ja vecāku klasei ir konstruktors ar vismaz vienu parametru, mums konstruktors jādeklarē apakšklasē un jāizmanto super skaidri uzaicināt vecāku konstruktoru. The super rezervētais vārds netiks automātiski pievienots, un kods bez tā netiks apkopots. Piemēram:

 public class CustomizedConstructorSuper {class Character {Character (String name) {System.out.println (nosaukums + "tika izsaukts"); }} klase Bārnijs paplašina rakstzīmi {// Mums būs sastādīšanas kļūda, ja mēs tieši neizsauksim konstruktoru // Mums tas jāpievieno Barney () {super ("Barney Gumble"); }}} 

Veidu liešana un ClassCastException

Apraide ir veids, kā skaidri paziņot kompilatoram, ka jūs patiešām plānojat pārveidot konkrēto tipu. Tas ir tāpat kā sakot: "Hei, JVM, es zinu, ko es daru, lūdzu, izvēlieties šo klasi ar šo tipu." Ja jūsu nodotā ​​klase nav saderīga ar deklarēto klases veidu, jūs saņemsiet ClassCastException.

Mantojumā mēs varam piešķirt bērnu klasi vecāku klasei bez casting, bet mēs nevaram piešķirt vecāku klasi bērnu klasei, neizmantojot casting.

Apsveriet šādu piemēru:

 public class CastingExample {public static void main (String ... castingExample) {Dzīvnieka dzīvnieks = jauns Dzīvnieks (); Suņu sunsDzīvnieks = (Suns) dzīvnieks; // Mēs iegūsim ClassCastException Dog dog = new Dog (); Dzīvnieku sunsWithAnimalType = jauns suns (); Suns specificDog = (suns) dogWithAnimalType; specificDog.bark (); Dzīvnieks citsSuns = suns; // Šeit ir labi, nav nepieciešams casting System.out.println ((((Suns) anotherDog)); // Tas ir vēl viens veids, kā mest objektu}} klase Dzīvnieks {} klase Suns izvelk dzīvnieku {void miza () {System.out.println ("Au au"); }} 

Kad mēs mēģinām iemest Dzīvnieks piemēram, a Suns mēs saņemam izņēmumu. Tas ir tāpēc, ka Dzīvnieks neko nezina par savu bērnu. Tas varētu būt kaķis, putns, ķirzaka utt. Nav informācijas par konkrēto dzīvnieku.

Problēma šajā gadījumā ir tā, ka mēs esam izveidojušies Dzīvnieks kā šis:

 Dzīvnieka dzīvnieks = jauns dzīvnieks (); 

Tad mēģināja to nodot šādi:

 Suņu sunsDzīvnieks = (Suns) dzīvnieks; 

Tāpēc, ka mums nav Suns piemēram, nav iespējams piešķirt Dzīvnieks uz Suns. Ja mēs mēģināsim, mēs iegūsim ClassCastException

Lai izvairītos no izņēmuma, mums būtu jāpiedalās Suns kā šis:

 Suņu suns = jauns suns (); 

tad piešķir to Dzīvnieks:

 Dzīvnieks citsSuns = suns; 

Šajā gadījumā, jo mēs esam pagarinājuši Dzīvnieks klase, Suns instanci pat nevajag nodot; Dzīvnieks vecāku klases tips vienkārši pieņem uzdevumu.

Casting ar supertipiem

Ir iespējams paziņot a Suns ar supertipu Dzīvnieks, bet, ja mēs vēlamies izmantot noteiktu metodi no Suns, mums tas būs jāraida. Piemēram, kā būtu, ja mēs gribētu izmantot miza () metodi? The Dzīvnieks supertipam nav iespējas precīzi zināt, kādu dzīvnieku gadījumu mēs izsaucam, tāpēc mums ir jāizmet Suns manuāli, pirms mēs varam izsaukt miza () metode:

 Dzīvnieku sunsWithAnimalType = jauns suns (); Suns specificDog = (suns) dogWithAnimalType; specificDog.bark (); 

Apraidi var izmantot arī nepiešķirot objektu klases tipam. Šī pieeja ir ērta, ja nevēlaties deklarēt citu mainīgo:

 System.out.println (((suns) cits suns)); // Tas ir vēl viens veids, kā nodot objektu 

Piedalieties Java mantojuma izaicinājumā!

Jūs esat iemācījies dažus svarīgus mantojuma jēdzienus, tāpēc tagad ir pienācis laiks izmēģināt mantojuma izaicinājumu. Lai sāktu, izpētiet šo kodu: