Kõik, mida peate teadma Java-i kindlate põhimõtete kohta



Sellest artiklist saate üksikasjalikult teada, millised on java tahked põhimõtted koos näidete ja nende olulisuse kohta tegelikus elus.

Maailmas (OOP), on palju disainijuhiseid, mustreid või põhimõtteid. Viis neist põhimõtetest on tavaliselt rühmitatud ja neid tuntakse lühendiga SOLID. Kuigi kõik need viis põhimõtet kirjeldavad midagi konkreetset, kattuvad need ka nii, et ühe neist omaks võtmine tähendab või viib teise omaksvõtmiseni. Selles artiklis mõistame JAVA SOLIDi põhimõtteid.

SOLID põhimõtete ajalugu Java-s

Robert C. Martin esitas viis objektorienteeritud kujunduspõhimõtet ja selle jaoks kasutatakse lühendit “S.O.L.I.D”. Kui kasutate kõiki S.O.L.I.D põhimõtteid kombineeritult, on teil hõlpsam hallata tarkvara väljatöötamine. S.O.L.I.D kasutamise muud omadused on:





  • See väldib koodilõhnu.
  • Kiiresti refraktorkood.
  • Oskab kohanevat või väledat tarkvaraarendust.

Kui kasutate kodeerimisel S.O.L.I.D põhimõtet, hakkate kirjutama nii tõhusat kui ka tõhusat koodi.



Mida tähendab S.O.L.I.D?

Solid esindab java viit põhimõtet, mis on:

  • S : Ühe vastutuse põhimõte
  • VÕI : Avatud-suletud põhimõte
  • L : Liskovi asenduspõhimõte
  • Mina : Liidese eraldamise põhimõte
  • D : Sõltuvuse inversiooni põhimõte

Selles blogis arutleme üksikasjalikult kõigi Java viie SOLID-põhimõtte üle.



Ühtse vastutuse põhimõte Java-s

Mida see ütleb?

Robert C. Martin kirjeldab seda nii, et ühel klassil peaks olema ainult üks ja ainus vastutus.

Ühe vastutuse põhimõtte kohaselt peaks olema ainult üks põhjus, mille tõttu klassi tuleb muuta. See tähendab, et klassil peaks olema üks ülesanne. Seda põhimõtet nimetatakse sageli subjektiivseks.

Põhimõttest saab näitega hästi aru. Kujutage ette, et on olemas klass, mis täidab järgmisi toiminguid.

  • Ühendatud andmebaasiga

  • Loe mõnda andmebaasitabelite andmeid

  • Lõpuks kirjutage see faili.

Kas olete stsenaariumi ette kujutanud? Siin on klassil muutmiseks mitu põhjust ja vähesed neist on failiväljundi muutmine, uue andmebaasi vastuvõtmine. Kui räägime ühtsest põhimõttelisest vastutusest, ütleksime, et klassi muutmiseks on seetõttu liiga palju põhjuseid, see ei sobi korralikult ühe vastutuse põhimõttega.

Näiteks võib Automobile klass ennast käivitada või peatada, kuid selle pesemine kuulub CarWash klassi. Teises näites on raamatuklassil omadused oma nime ja teksti salvestamiseks. Kuid raamatu printimise ülesanne peab kuuluma raamatuprinteri klassi. Raamatuprinteri klass võib printida konsoolile või mõnele muule andmekandjale, kuid sellised sõltuvused eemaldatakse raamatuklassist

Miks seda põhimõtet nõutakse?

Kui järgitakse ühtse vastutuse põhimõtet, on testimine lihtsam. Ühe vastutuse korral on klassil vähem proovijuhte. Vähem funktsionaalsust tähendab ka vähem sõltuvusi teistest klassidest. See toob kaasa parema koodikorralduse, kuna väiksemaid ja korralikumaid klasse on lihtsam otsida.

Näide selle põhimõtte selgitamiseks:

Oletame, et teil palutakse juurutada teenus UserSetting, kus kasutaja saab seadeid muuta, kuid enne seda tuleb kasutaja autentida. Üks viis selle rakendamiseks oleks:

public class UserSettingService {public void changeEmail (Kasutajakasutaja) {if (checkAccess (kasutaja)) {// Muutmise valiku lubamine}} avalik boolean checkAccess (Kasutajakasutaja) {// Kontrollige, kas kasutaja on kehtiv. }}

Kõik näeb hea välja, kuni soovite checkAccess-koodi mõnes muus kohas uuesti kasutada VÕI soovite muuta checkAccess-i toimimise viisi. Kõigil kahel juhul muutsite lõpuks sama klassi ja esimesel juhul peate ka juurdepääsu kontrollimiseks kasutama UserSettingService'i.
Üks võimalus seda parandada on jaotada UserSettingService kasutajateks UserSettingService ja SecurityService. Ja teisaldage checkAccess kood SecurityService'i.

public class UserSettingService {public void changeEmail (User user) {if (SecurityService.checkAccess (user)) {// Muutmise võimalus}}}} public class SecurityService {public static boolean checkAccess (User user) {// kontrollige juurdepääsu. }}

Avatud Java suletud põhimõte

Robert C. Martin kirjeldab seda, et tarkvarakomponendid peaksid olema laiendamiseks avatud, kuid muutmiseks suletud.

Täpsus on see, et selle põhimõtte kohaselt tuleks klass kirjutada nii, et see täidaks oma tööd laitmatult, eeldamata, et tulevikus inimesed lihtsalt tulevad ja muudavad seda. Seega peaks klass muutmiseks suletud olema, kuid sellel peaks olema võimalus laiendada. Klassi pikendamise viisid on järgmised:

Avatud-suletud põhimõtte suurepärast näidet saab mõista brauserite abil. Kas mäletate Chrome'i brauserisse laienduste installimist?

Kroomibrauseri põhiülesanne on surfata erinevates saitides. Kas soovite kontrollida Chrome'i brauseri abil meilisõnumite kirjutamisel grammatikat? Kui jah, saate lihtsalt kasutada Grammarly laiendust, see annab teile sisu grammatika kontrolli.

See mehhanism, kuhu lisate asju brauseri funktsionaalsuse suurendamiseks, on laiendus. Seega on brauser suurepärane näide funktsionaalsusest, mis on laienduseks avatud, kuid modifitseerimiseks suletud. Lihtsate sõnadega saate funktsionaalsust täiustada, lisades / installides brauserisse pistikprogramme, kuid ei saa midagi uut ehitada.

Miks seda põhimõtet nõutakse?

OCP on oluline, kuna tunnid võivad meile tulla kolmandate osapoolte raamatukogude kaudu. Peaksime saama neid klasse pikendada muretsemata, kas need baasklassid saavad meie laiendusi toetada. Kuid pärimine võib viia alamklassideni, mis sõltuvad baasklassi rakendamisest. Selle vältimiseks on soovitatav kasutada liideseid. See täiendav abstraktsioon viib lahtise haakumiseni.

Ütleme nii, et peame arvutama erineva kujuga alad. Alustame klassi loomisega meie esimesele kujule Ristkülikmillel on 2 atribuudi pikkust& laius.

avalik klass Ristkülik {public double length public double width}

Järgmisena loome klassi selle ristküliku pindala arvutamiseksmille meetod on arvutadaRistküliku pindalamis võtab ristkülikusisendparameetrina ja arvutab selle pindala.

avalik klass AreaCalculator {public double arvutadaRectangleArea (Rectangle rectangle) {return rectangle.length * rectangle.width}}

Siiamaani on kõik korras. Oletame, et saame oma teise kuju ringi. Nii loome kohe uue klassi ringiühe atribuudiraadiusega.

avalik klass Ring {public double radius}

Seejärel muudame alaarvutitklass, et lisada ringarvutused uue meetodi abil arvutaCircleaArea ()

avalik klass AreaCalculator {avalik kahekordne arvutusRistküliku pindala (ristküliku ristkülik) {tagasiside ristkülik.pikkus * ristkülik.laius} avalik topeltarvutaRingi pindala (ringjoon) {tagastus (22/7) * ring.raadius * ring.raadius}}

Pange siiski tähele, et ülaltoodud lahenduse kujundamisel oli vigu.

Oletame, et meil on uue kujuga viisnurk. Sel juhul muudame jällegi klassi AreaCalculator. Kujunditüüpide kasvades muutub see muutuvaks, kuna AreaCalculator muutub pidevalt ja kõik selle klassi tarbijad peavad jätkama AreaCalculatorit sisaldavate teekide värskendamist. Selle tulemusel ei arvutata (lõplikult) AreaCalculator klassi käendusega, sest iga kord, kui uus kuju tuleb, muudetakse seda. Niisiis, see disain pole modifitseerimiseks suletud.

AreaCalculator peab jätkama oma arvutusloogika lisamist uuematesse meetoditesse. Me ei laienda tegelikult kujundite ulatust, pigem teeme iga lisatud kuju jaoks tükk-eine (bit-by-bit) lahenduse.

Ülaltoodud disaini muutmine avatud / suletud põhimõtte järgimiseks:

Vaatame nüüd elegantsemat kujundust, mis lahendab ülaltoodud kujunduse vead, järgides avatud / suletud põhimõtet. Kõigepealt muudame disaini laiendatavaks. Selleks peame kõigepealt määrama aluse tüübi Shape ja laskma Circle & Rectangle Shape'i liidese.

avalik liides Kuju {public double arvuta pindala ()} public class Ristkülik realiseerib kuju {topeltpikk topeltlaius public double aprēķinaala () {return pikkus * laius}} public class Circle rakendab kuju {public double radius public double aprēķinaala () {return (22 / 7) * raadius * raadius}}

Seal on baasliidese kuju. Kõik kujundid rakendavad nüüd baasliidese kuju. Kujuliidesel on abstraktne meetod calcArea (). Mõlemad ringid ja ristkülikud pakuvad oma atribuutide abil meetodit CalcArea () enda alistatud rakendamist.
Oleme toonud sisse teatava laiendatavuse, kuna kujundid on nüüd Shape-liideste näide. See võimaldab meil kasutada üksikute klasside asemel Shape'i
Viimane punkt eespool mainis nende kujundite tarbijat. Meie puhul on tarbija klass AreaCalculator, mis näeks nüüd välja selline.

avalik klass AreaCalculator {public double aprēķetaShapeArea (kuju kuju) {return shape.calculateArea ()}}

See AreaCalculatorklass eemaldab nüüd täielikult meie ülalnimetatud disainivead ja annab puhta lahenduse, mis järgib avatud-suletud põhimõtet. Jätkame Java teiste SOLID-põhimõtetega

Liskovi asendusprintsiip Java keeles

Robert C. Martin kirjeldab seda, et tuletatud tüübid peavad olema nende põhitüübid täielikult asendatavad.

Liskovi asenduspõhimõte eeldab, et q (x) on omadus, mida saab tõestada tüübi T kuuluvate x-i üksuste kohta. Nüüd peaks selle põhimõtte kohaselt q (y) olema nüüd tõestatav objektidele y, mis kuuluvad tüüpi S, ja S on tegelikult T alamtüüp. Kas olete nüüd segaduses ega tea, mida Liskovi asenduspõhimõte tegelikult tähendab? Selle määratlus võib olla natuke keeruline, kuid tegelikult on see üsna lihtne. Ainus asi on see, et iga alaklass või tuletatud klass peaksid olema asendatavad nende vanema- või põhiklassiga.

Võite öelda, et see on ainulaadne objektorienteeritud põhimõte. Põhimõtet saab veelgi lihtsustada konkreetse vanematüübi lastetüübil ilma komplikatsioone tekitamata või asju õhku laskmata peaks olema võimalus selle vanema eest seista. See põhimõte on tihedalt seotud Liskovi asendamise põhimõttega.

Miks seda põhimõtet nõutakse?

Sellega välditakse pärandi väärkasutamist. See aitab meil olla vastavuses suhtega 'on-a'. Võime öelda ka seda, et alaklassid peavad täitma baasklassi määratletud lepingu. Selles mõttes on see seotudKujundus lepingu järgiseda kirjeldas esimest korda Bertrand Meyer. Näiteks on ahvatlev öelda, et ring on teatud tüüpi ellips, kuid ringidel pole kahte fookust ega duuri / molli telge.

LSP-d selgitatakse rahva abil ruudu- ja ristkülikunäite abil. kui eeldame ISA suhet Ruudu ja Ristküliku vahel. Seega nimetame 'ruut on ristkülik'. Allolev kood tähistab suhet.

avalik klass Ristkülik {private int length private int widthth public int getLength () {return length} public void setLength (int length) {this.length = length} public int getBreadth () {return width} public void setBreadth (int width) { this.breadth = width} public int getArea () {return this.length * this.breadth}}

Allpool on ruutu kood. Pange tähele, et ruut laiendab ristkülikut.

kuidas iteraatorit kasutada
avaliku klassi ruut laieneb ristkülik {public void setBreadth (int widthth) {super.setBreadth (width) super.setLength (width)} public void setLength (int length) {super.setLength (length) super.setBreadth (length)}}

Sel juhul püüame luua ruudu ja ristküliku vahel ISA-seose, nii et allpool olevas koodis ruudu nimetamine ristkülikuks hakkaks ootamatult käituma, kui ruudu eksemplar läbitakse. Piirkonna kontrollimise ja laiuse kontrollimise korral visatakse tõendusviga, kuigi programm lõpetatakse, kuna väide piirkontrolli ebaõnnestumise tõttu visatakse tõendisse.

avalik klass LSPDemo {public void calcArea (Rectangle r) {r.setBreadth (2) r.setLength (3) väidavad r.getArea () == 6: printError ('area', r) väidavad r.getLength () == 3: printError ('length', r) väidab r.getBreadth () == 2: printError ('width', r)} private String printError (String errorIdentifer, Rectangle r) {return 'Ootamatu väärtus' + errorIdentifer + ' näiteks '+ r.getClass (). getName ()} public static void main (String [] args) {LSPDemo lsp = new LSPDemo () // Ristküliku eksemplar edastatakse lsp.calculateArea (uus ristkülik ()) // Ruudu eksemplar on edastatud lsp.calculateArea (new Square ())}}

Klass demonstreerib Liskovi asendamise põhimõtet (LSP) Põhimõtte kohaselt peavad funktsioonid, mis kasutavad viiteid baasklassidele, saama tuletatud klassi objekte kasutada seda teadmata.

Seega peaks allpool toodud näites funktsioon Ruutkülikut kasutav arvutusala arvutama suutma kasutada tuletatud klassi objekte nagu Ruut ja täita ristküliku definitsiooni nõudeid. Tuleb märkida, et vastavalt ristküliku määratlusele peab alltoodud andmeid arvestades alati järgima järgmist:

  1. Pikkus peab alati olema võrdne meetodi sisestatud pikkusega setLength
  2. Laius peab alati olema võrdne meetodi setBreadth sisendina antud laiusega
  3. Pindala peab alati olema võrdne pikkuse ja laiuse korrutisega

Juhul, kui proovime luua ruudu ja ristküliku vahelise ISA-seose nii, et seda nimetatakse 'ruut on ristkülik', siis ülaltoodud kood hakkaks ootamatult käituma, kui ruudu eksemplar läbitakse. Pindala ja kontrollimise korral visatakse viga laius, kuigi programm lõpetatakse, kuna väide tõrjutakse ala kontrolli ebaõnnestumise tõttu.

Klass Square ei vaja selliseid meetodeid nagu setBreadth või setLength. Klass LSPDemo peaks teadma ristküliku tuletatud klasside üksikasju (näiteks ruut), et viskevea vältimiseks sobivalt kodeerida. Olemasoleva koodi muutmine rikub ennekõike avatud-suletud põhimõtet.

Liidese eraldamise põhimõte

Robert C. Martin kirjeldab seda, et kliente ei tohiks sundida kasutama mittevajalikke meetodeid, mida nad ei kasuta.

VastavaltLiidese eraldamise põhimõteklient, hoolimata sellest, mida ei tohiks kunagi sundida kasutama liidest, mida ta ei kasuta, või klient ei tohiks kunagi olla kohustatud sõltuma mis tahes meetodist, mida nad ei kasuta. Nii et põhimõtteliselt on liidese eraldamise põhimõtted, nagu eelistate liidesed, mis on väikesed, kuid kliendispetsiifilised monoliitse ja suurema liidese asemel. Lühidalt öeldes oleks halb, kui sunniksite klienti sõltuma teatud asjast, mida nad ei vaja.

Näiteks on logide kirjutamiseks ja lugemiseks üks logimisliides andmebaasi jaoks kasulik, kuid mitte konsooli jaoks. Logide lugemisel pole konsoolilogeril mõtet. Selle Java-i artikli SOLID Principles jätkamine.

Miks seda põhimõtet nõutakse?

Oletame, et on olemas restorani liides, mis sisaldab meetodeid tellimuste vastuvõtmiseks veebiklientidelt, sissehelistamis- või telefoniklientidelt ja klientidelt. See sisaldab ka meetodeid veebimaksete (võrguklientidele) ja isiklike maksete (sisseostetud klientidele ja telefoniklientidele, kui nende tellimus koju toimetatakse) käsitlemiseks.

Nüüd looge restoranile Java-liides ja nimetage see nimeks RestaurantInterface.java.

avalik liides RestaurantInterface {public void acceptOnlineOrder () public void takeTelephoneOrder () public void payOnline () public void walkInCustomerOrder () public void payInPerson ()}

Restoran Interface'is on määratletud 5 meetodit, mis on mõeldud veebitellimuste vastuvõtmiseks, telefonitellimuste vastuvõtmiseks, tellimuste vastuvõtmiseks sissetöötatud kliendilt, veebipõhise makse aktsepteerimiseks ja isiklikult makse aktsepteerimiseks.

Alustame võrguklientidele mõeldud RestaurantInterface'i juurutamisega kui OnlineClientImpl.java

avalik klass OnlineClientImpl rakendab RestaurantInterface'i {public void acceptOnlineOrder () {// võrgutellimuse esitamise loogika} public void takeTelephoneOrder () {// Pole rakendatav veebitellimuse jaoks uus UnsupportedOperationException ()} public void payOnline () {// maksmise loogika võrgus} public void walkInCustomerOrder () {// Ei kehti veebitellimuste korral, visake uus UnsupportedOperationException ()} public void payInPerson () {// Ei kehti veebitellimuste jaoks uus UnsupportedOperationException ()}}
  • Kuna ülaltoodud kood (OnlineClientImpl.java) on mõeldud veebitellimuste jaoks, visake UnsupportedOperationException.

  • Veebi-, telefoni- ja sissejuhatavad kliendid kasutavad igaühe jaoks spetsiaalset RestaurantInterface'i rakendust.

  • Telephonicu kliendi ja Walk-in-kliendi juurutusklassidel on toetamata meetodid.

  • Kuna viis meetodit on osa RestaurantInterface'ist, peavad rakendusklassid kõik need viis rakendama.

  • Meetodid, mida iga juurutusklass viskab UnsupportedOperationException. Nagu selgelt näete - kõigi meetodite rakendamine on ebaefektiivne.

  • Kõik muudatused RestaurantInterface'i mis tahes meetodis levitatakse kõikides rakendusklassides. Seejärel hakkab koodi hooldus muutuma tõeliselt tülikaks ja muudatuste regressiooniefektid suurenevad pidevalt.

  • RestaurantInterface.java rikub ühtse vastutuse põhimõtet, kuna nii maksete kui ka tellimuste esitamise loogika on koondatud ühte liidesesse.

Eespool nimetatud probleemide ületamiseks rakendame ülaltoodud kujunduse refaktoriks liidese eraldamise põhimõtet.

  1. Eraldage makse- ja tellimuste esitamise funktsioonid kaheks eraldi lahjaks liideseks - PaymentInterface.java ja OrderInterface.java.

  2. Iga klient kasutab ühte makseviisi ja tellimuse liidese rakendust. Näiteks - OnlineClient.java kasutab OnlinePaymentImpli ja OnlineOrderImpli jne.

  3. Ühe vastutuse põhimõte on nüüd lisatud makseliidesena (PaymentInterface.java) ja tellimisliidesena (OrderInterface).

  4. Ühe tellimuse või makseliidese muudatus ei mõjuta teist. Nad on nüüd iseseisvad. Pole vaja teha näivrakendusi ega visata UnsupportedOperationExceptionit, kuna igal liidesel on ainult meetodid, mida ta alati kasutab.

Pärast Interneti-teenuse pakkuja rakendamist

mis on peakokk devopsis

Sõltuvuse ümberpööramise põhimõte

Robert C. Martin kirjeldab seda, kuna see sõltub abstraktsioonidest, mitte konkretsioonidest. Selle kohaselt ei tohi kõrgetasemeline moodul kunagi tugineda ühele madalama moodulile. näiteks

Lähete kohalikku poodi midagi ostma ja otsustate selle eest maksta oma deebetkaardi abil. Seega, kui annate oma kaardi ametnikule makse sooritamiseks, ei viitsi ametnik kontrollida, millise kaardi olete andnud.

Isegi kui olete andnud Visa kaardi, ei pane ta teie kaardi pühkimiseks Visa masinat välja. Krediit- või deebetkaardi tüüp, mille maksmiseks teil on, pole isegi tähtis, kui nad lihtsalt selle pühivad. Nii et selles näites näete, et nii teie kui ka ametnik sõltuvad krediitkaardi võtmisest ja te ei muretse kaardi eripära pärast. See on sõltuvuse inversiooni põhimõte.

Miks seda põhimõtet nõutakse?

See võimaldab programmeerijal eemaldada kõvakodeeritud sõltuvused, nii et rakendus muutub vabalt ühendatud ja laiendatavaks.

avaliku klassi õpilane {privaatse aadressi aadress avalik õpilane () {aadress = uus aadress ()}}

Ülalolevas näites nõuab õpilaseklass aadressiobjekti ja see vastutab objekti Aadress initsialiseerimise ja kasutamise eest. Kui aadressiklassi tulevikus muudetakse, peame muudatusi tegema ka õpilaste tunnis. See muudab õpilase ja aadressi objektide tiheda ühendamise. Selle probleemi saame lahendada sõltuvuse inversiooni kujundusmustri abil. st Aadressiobjekt rakendatakse iseseisvalt ja antakse õpilasele, kui õpilane on instantsitud konstruktori- või setteripõhise sõltuvuse inversiooni abil.

Sellega jõuame selle Java-põhise SOLID-põhimõtte lõpuni.

Vaadake Edureka, usaldusväärne veebiõppeettevõte, mille võrgustik hõlmab üle 250 000 rahuloleva õppija, levinud üle kogu maailma. Edureka Java J2EE ja SOA koolitus- ja sertifitseerimiskursus on mõeldud õpilastele ja spetsialistidele, kes soovivad olla Java arendajad. Kursus on loodud selleks, et anda teile Java programmeerimises edukas algus ja õpetada teid nii Java-põhiprogrammide kui ka edasijõudnute mõistete ning erinevate Java-raamistike, näiteks Hibernate & Spring, jaoks.

Kas teil on meile küsimus? Palun mainige seda selle blogi „SOLID Principles in Java“ kommentaaride osas ja võtame teiega ühendust niipea kui võimalik.