Vse, kar morate vedeti o trdnih načelih v Javi



V tem članku boste podrobno izvedeli, kaj so trdna načela v javi s primeri in njihov pomen v resničnem življenju.

V svetu (OOP), obstaja veliko smernic, vzorcev ali načel oblikovanja. Pet od teh načel je običajno združenih in jih poznamo pod kratico SOLID. Medtem ko vsako od teh petih načel opisuje nekaj posebnega, se prekrivajo tudi tako, da sprejetje enega od njih pomeni ali vodi do sprejetja drugega. V tem članku bomo razumeli SOLID Principles in Java.

Zgodovina SOLID načel v Javi

Robert C. Martin je podal pet objektno usmerjenih načel oblikovanja, zanj pa se uporablja kratica 'S.O.L.I.D'. Ko kombinirate vsa načela S.O.L.I.D, vam postane lažje razviti programsko opremo, ki jo je mogoče enostavno upravljati. Druge značilnosti uporabe S.O.L.I.D so:





  • Izogiba se vonjem kode.
  • Hitro refrakcijska koda.
  • Lahko prilagodljiv ali gibčen razvoj programske opreme.

Ko pri kodiranju uporabite princip S.O.L.I.D, začnete pisati tako učinkovito in uspešno kodo.



Kakšen je pomen S.O.L.I.D?

Solid predstavlja pet načel Java, ki so:

  • S : Načelo enotne odgovornosti
  • ALI : Načelo odprto-zaprto
  • L : Liskov princip zamenjave
  • jaz : Načelo ločevanja vmesnikov
  • D : Načelo inverzije odvisnosti

V tem blogu bomo podrobno obravnavali vseh pet SOLID načel Java.



Načelo enotne odgovornosti v Javi

Kaj pravi?

Robert C. Martin opisuje, da bi moral imeti en razred samo eno in edino odgovornost.

razvrščanje polja c ++

V skladu z načelom enotne odgovornosti bi moral obstajati samo en razlog, zaradi katerega je treba spremeniti razred. Pomeni, da mora imeti razred eno nalogo. To načelo pogosto imenujemo subjektivno.

Načelo lahko dobro razumemo s primerom. Predstavljajte si, da obstaja razred, ki izvaja naslednje operacije.

  • Povezan z bazo podatkov

  • Preberite nekaj podatkov iz tabel baz podatkov

  • Na koncu jo zapišite v datoteko.

Ste si zamislili scenarij? Tu ima razred več razlogov za spremembo, med katerimi je le nekaj sprememb izhodnih datotek, sprejemanje nove baze podatkov. Ko govorimo o odgovornosti enega samega načela, bi rekli, da je preveč razlogov, da se razred spremeni, zato se ne ujema pravilno z načelom enotne odgovornosti.

Na primer, avtomobilski razred se lahko sam zažene ali ustavi, vendar naloga njegovega pranja spada v razred CarWash. V drugem primeru ima razred Book lastnosti za shranjevanje lastnega imena in besedila. Toda naloga tiskanja knjige mora pripadati razredu Tiskalnik knjig. Razred tiskalnika knjig se lahko tiska na konzolo ali drug medij, vendar so takšne odvisnosti odstranjene iz razreda knjige

Zakaj je to načelo obvezno?

Ko se upošteva načelo enotne odgovornosti, je testiranje lažje. Z eno odgovornostjo bo imel razred manj testnih primerov. Manj funkcionalnosti pomeni tudi manj odvisnosti od drugih razredov. To vodi k boljši organizaciji kode, saj je manjše in dobro namenjene razrede lažje iskati.

Primer pojasnitve tega načela:

Recimo, da ste pozvani, da izvedete storitev UserSetting, pri kateri lahko uporabnik spremeni nastavitve, vendar je treba pred tem preveriti pristnost uporabnika. Eden od načinov za izvajanje tega bi bil:

javni razred UserSettingService {public void changeEmail (User user) {if (checkAccess (user)) {// Dovoli možnost za spremembo}} public boolean checkAccess (User user) {// Preverite, ali je uporabnik veljaven. }}

Vse izgleda dobro, dokler ne želite znova uporabiti kode checkAccess na katerem koli drugem mestu ali pa želite spremeniti način izvajanja checkAccess. V vseh dveh primerih bi na koncu spremenili isti razred, v prvem primeru pa bi morali uporabiti UserSettingService tudi za preverjanje dostopa.
Eden od načinov za odpravo tega je razgradnja UserSettingService v UserSettingService in SecurityService. In kodo checkAccess premaknite v SecurityService.

javni razred UserSettingService {public void changeEmail (User user) {if (SecurityService.checkAccess (user)) {// Dovoli možnost za spremembo}}} public class SecurityService {public static boolean checkAccess (User user) {// preveri dostop. }}

Odprite zaprto načelo v Javi

Robert C. Martin to opisuje kot komponente programske opreme, ki bi morale biti odprte za razširitev, vendar zaprte za spreminjanje.

Natančneje, po tem načelu bi moral biti razred napisan tako, da svoje delo opravlja brezhibno, ne da bi predpostavljali, da ga bodo ljudje v prihodnosti preprosto prišli in zamenjali. Zato bi moral razred za spremembo ostati zaprt, vendar bi moral imeti možnost razširitve. Načini razširitve razreda vključujejo:

  • Dedovanje iz razreda

  • Prepisovanje zahtevanega vedenja razreda

  • Razširitev določenega vedenja razreda

Odličen primer načela odprto-zaprto lahko razumemo s pomočjo brskalnikov. Se spomnite namestitve razširitev v brskalnik Chrome?

Osnovna funkcija brskalnika chrome je brskanje po različnih spletnih mestih. Ali želite preveriti slovnico, ko pišete e-pošto z brskalnikom chrome? Če je odgovor pritrdilen, lahko preprosto uporabite razširitev Grammarly, ki vam omogoča preverjanje slovnice vsebine.

Ta mehanizem, v katerega dodajate stvari za povečanje funkcionalnosti brskalnika, je razširitev. Zato je brskalnik odličen primer funkcionalnosti, ki je odprta za razširitev, vendar je zaprta za spremembo. Z enostavnimi besedami lahko izboljšate funkcionalnost z dodajanjem / nameščanjem vtičnikov v brskalnik, vendar ne morete zgraditi nič novega.

Zakaj je to načelo potrebno?

OCP je pomemben, saj lahko predavanja k nam prihajajo prek neodvisnih knjižnic. Te razrede bi lahko lahko razširili, ne da bi se skrbeli, če ti osnovni razredi lahko podpirajo naše razširitve. Toda dedovanje lahko privede do podrazredov, ki so odvisni od izvedbe osnovnega razreda. Da bi se temu izognili, je priporočljiva uporaba vmesnikov. Ta dodatna abstrakcija vodi do ohlapne sklopke.

Recimo, da moramo izračunati površine različnih oblik. Začnemo z ustvarjanjem razreda za naš prvi pravokotnik v oblikiki ima 2 atributa dolžine& premer.

javni razred Pravokotnik {javna dvojna dolžina javna dvojna širina}

Nato ustvarimo razred za izračun površine tega pravokotnikaki ima metodo izračunajRectangleAreaki vzame pravokotnikkot vhodni parameter in izračuna njegovo površino.

javni razred AreaCalculator {javni dvojni izračunRectangleArea (pravokotnik pravokotnika) {vrni pravokotnik.dolžina * pravokotnik.širina}}

Zaenkrat dobro. Zdaj recimo, da dobimo naš drugi krog oblike. Tako takoj ustvarimo nov razred Krogz enim polmerom atributa.

javni krog {javni dvojni radij}

Nato spremenimo Areacalculatorrazred za dodajanje izračunov kroga z novo metodo izračunajCircleaArea ()

javni razred AreaCalculator {javni dvojni izračunRectangleArea (pravokotnik pravokotnika) {vrnitev rectangle.length * rectangle.width} javni dvojni izračunCircleArea (krog kroga) {return (22/7) * circle.radius * circle.radius}}

Vendar upoštevajte, da je bilo v načinu, kako smo zgoraj oblikovali svojo rešitev, pomanjkljivosti.

Recimo, da imamo novo obliko pentagona. V tem primeru bomo spet spremenili razred AreaCalculator. Ko naraščajo oblike, to postaja bolj zapleteno, saj se AreaCalculator nenehno spreminja in vsi potrošniki tega razreda bodo morali še naprej posodabljati svoje knjižnice, ki vsebujejo AreaCalculator. Posledično razred AreaCalculator ne bo zagotovo izhodiščen (dokončan), saj bo vsakič, ko pride nova oblika, spremenjen. Torej, ta zasnova ni zaprta za spremembe.

AreaCalculator bo moral še naprej dodajati svojo računsko logiko v novejših metodah. Območja oblik v resnici ne širimo, temveč preprosto naredimo rešitev po delih (po delcih) za vsako obliko, ki jo dodamo.

Sprememba zgornje zasnove v skladu z načelom odprto / zaprto:

Oglejmo si zdaj bolj eleganten dizajn, ki odpravlja pomanjkljivosti v zgornjem oblikovanju z upoštevanjem odprtega / zaprtega načela. Najprej bomo oblikovanje naredili razširljivo. Za to moramo najprej definirati osnovni tip Shape in imeti Circle & Rectangle, ki izvaja vmesnik Shape.

javni vmesnik Oblika {javni dvojni izračunArea ()} javni razred Pravokotnik izvaja Oblika {dvojna dolžina dvojna širina javni dvojni izračunArea () {vrnjena dolžina * širina}} javni razred Krog izvaja Oblika {javni dvojni radij javni dvojni izračunArea () {return (22 / 7) * polmer * polmer}}

Obstaja osnovni vmesnik Shape. Vse oblike zdaj izvajajo osnovni vmesnik Shape. Vmesnik oblike ima abstraktno metodo calcuArea (). Krog in pravokotnik zagotavljata lastno razveljavljeno izvajanje metode CalcuArea () z lastnimi atributi.
Dosegli smo določeno stopnjo razširljivosti, saj so oblike zdaj primerek vmesnikov Shape. To nam omogoča, da namesto posameznih razredov uporabljamo obliko
Zadnja točka zgoraj omenjeni potrošnik teh oblik. V našem primeru bo potrošnik razred AreaCalculator, ki bi bil zdaj videti tako.

javni razred AreaCalculator {javni dvojni izračunShapeArea (Oblika oblike) {return shape.calculateArea ()}}

Ta AreaCalculatorclass zdaj popolnoma odstrani zgoraj omenjene napake v oblikovanju in daje čisto rešitev, ki upošteva odprto-zaprto načelo. Nadaljujmo z drugimi SOLID Načeli v Javi

Načelo substitucije Liskov v Javi

Robert C. Martin to opisuje kot izpeljane tipe, ki jih je treba popolnoma nadomestiti s svojimi osnovnimi tipi.

Načelo substitucije Liskov predpostavlja, da je q (x) lastnost, ki jo je mogoče dokazati o entitetah x, ki pripada tipu T. Zdaj bi moralo biti po tem načelu q (y) zdaj dokazljivo za objekte y, ki spadajo v tip S, in S je pravzaprav podvrsta T. Ste zdaj zmedeni in ne veste, kaj Liskov princip zamenjave dejansko pomeni? Njegova opredelitev je lahko nekoliko zapletena, v resnici pa je dokaj enostavna. Edina stvar je, da bi moral biti vsak podrazred ali izpeljani razred nadomestljiv s svojim nadrejenim ali osnovnim razredom.

Lahko rečete, da gre za edinstveno objektno usmerjeno načelo. Načelo lahko nadalje poenostavi podrejeni tip določene vrste staršev, ne da bi se zapletlo ali razstrelilo stvari, ki bi morale biti sposobne zastopati tega starša. To načelo je tesno povezano z načelom nadomestitve Liskov.

Zakaj je to načelo potrebno?

S tem se izognemo zlorabi dediščine. Pomaga nam, da se prilagodimo razmerju »je-a«. Lahko rečemo tudi, da morajo podrazredi izpolnjevati pogodbo, ki jo definira osnovni razred. V tem smislu je povezano zOblikovanje po pogodbito je prvi opisal Bertrand Meyer. Na primer, skušnjava je reči, da je krog vrsta elipse, vendar krogi nimajo dveh žarišč ali večjih / manjših osi.

LSP je priljubljeno razložen na primeru kvadrata in pravokotnika. če predpostavimo razmerje ISA med kvadratom in pravokotnikom. Tako imenujemo »Kvadrat je pravokotnik«. Spodnja koda predstavlja odnos.

javni razred Pravokotnik {private int length private int widthth public int getLength () {return length} public void setLength (int length) {this.length = length} public int getBreadth () {return widthth} javna void setBreadth (int širina) { this.breadth = širina} public int getArea () {return this.length * this.breadth}}

Spodaj je koda za Square. Upoštevajte, da kvadrat razširja pravokotnik.

java casting double to int
javni razred Square se razširi Pravokotnik {javna praznina setBreadth (int širina) {super.setBreadth (širina) super.setLength (širina)} javna praznina setLength (int dolžina) {super.setLength (dolžina) super.setBreadth (dolžina)}}

V tem primeru poskušamo vzpostaviti razmerje ISA med kvadratom in pravokotnikom, tako da bi se klic 'Square is Rectangle' v spodnji kodi začel obnašati nepričakovano, če bi primer Square prenesen. V primeru preverjanja »Območje« in »Širine« se prikaže napaka pri trditvi, čeprav se program zaključi, ko napaka pri trditvi vrne zaradi neuspešnega preverjanja Območja.

javni razred LSPDemo {javna praznina izračunaj površino (pravokotnik r) {r.setBreadth (2) r.setLength (3) uveljavi r.getArea () == 6: printError ('area', r) assert r.getLength () == 3: printError ('length', r) assert r.getBreadth () == 2: printError ('width', r)} private String printError (String errorIdentifer, Rectangle r) {return 'Nepričakovana vrednost' + errorIdentifer + ' na primer '+ r.getClass (). getName ()} javna statična void main (String [] args) {LSPDemo lsp = new LSPDemo () // Primerek Rectangle se prenese lsp.calculateArea (new Rectangle ()) // Posreduje se primerek kvadrata lsp.calculateArea (new Square ())}}

Razred dokazuje načelo nadomestitve Liskov (LSP) V skladu z načelom morajo funkcije, ki uporabljajo sklice na osnovne razrede, imeti možnost uporabe predmetov izpeljanega razreda, ne da bi to vedele.

Tako bi morala v primeru, prikazanem spodaj, funkcija izračunati območje, ki uporablja sklic 'Pravokotnik', uporabiti predmete izvedenega razreda, kot je kvadrat, in izpolniti zahtevo, ki jo postavlja definicija pravokotnika. Upoštevati je treba, da morajo v skladu z definicijo pravokotnika glede na spodnje podatke vedno veljati:

  1. Dolžina mora biti vedno enaka dolžini, ki je bila podana kot vhod v metodo, setLength
  2. Širina mora biti vedno enaka širini, podani kot vhod v metodo, setBreadth
  3. Površina mora biti vedno enaka zmnožku dolžine in širine

V primeru, da poskušamo vzpostaviti razmerje ISA med kvadratom in pravokotnikom tako, da imenujemo »kvadrat je pravokotnik«, bi se zgornja koda začela obnašati nepričakovano, če je primer kvadrata sprejet. V primeru preverjanja površine in preverjanja bo vržena napaka trditve za širino, čeprav se bo program zaključil, ko bo napaka trditve vržena zaradi neuspešnega preverjanja območja.

Razred Square ne potrebuje metod, kot sta setBreadth ali setLength. Razred LSPDemo bi moral poznati podrobnosti izvedenih razredov pravokotnika (kot je kvadrat), da bi ustrezno kodiral, da bi se izognili napaki pri metanju. Sprememba obstoječe kode v prvi vrsti krši načelo odprto-zaprto.

Načelo ločevanja vmesnikov

Robert C. Martin to opisuje, saj stranke ne bi smeli prisiliti k izvajanju nepotrebnih metod, ki jih ne bodo uporabljali.

Po navedbahNačelo ločevanja vmesnikovodjemalca, ne glede na to, česa nikoli ne bi smeli prisiliti k izvajanju vmesnika, ki ga ne uporablja, ali od odjemalca nikoli ne bi smeli biti zavezani, da je odvisen od katere koli metode, ki je ne uporabljajo. Torej, načela ločevanja vmesnikov, vmesniki, ki so majhni, a specifični za odjemalca namesto monolitnega in večjega vmesnika. Skratka, slabo bi bilo, če bi prisilili odjemalca, da je odvisen od določene stvari, ki je ne potrebuje.

Na primer, en vmesnik za beleženje in pisanje dnevnikov je koristen za bazo podatkov, ne pa tudi za konzolo. Branje dnevnikov za zapisovalnik konzole nima smisla. Nadaljujemo s tem člankom SOLID Principles in Java.

Zakaj je to načelo potrebno?

Recimo, da obstaja restavracijski vmesnik, ki vsebuje metode za sprejemanje naročil spletnih kupcev, klicnih ali telefonskih strank in vhodnih strank. Vsebuje tudi načine za obdelavo spletnih plačil (za spletne kupce) in osebna plačila (za vstopne stranke in telefonske stranke, ko je njihovo naročilo dostavljeno doma).

Zdaj pa ustvarimo vmesnik Java za restavracijo in ga poimenujmo kot RestaurantInterface.java.

javni vmesnik RestaurantInterface {public void acceptOnlineOrder () public void takeTelephoneOrder () public void payOnline () public void walkInCustomerOrder () public void payInPerson ()}

V RestaurantInterface je opredeljenih 5 načinov za sprejemanje spletnega naročila, sprejemanje telefonskega naročila, sprejemanje naročil od vstopne stranke, sprejemanje spletnega plačila in osebno sprejemanje plačil.

Začnimo z izvajanjem RestaurantInterface za spletne stranke kot OnlineClientImpl.java

javni razred OnlineClientImpl implementira RestaurantInterface {public void acceptOnlineOrder () {// logika za oddajo spletnega naročila} public void takeTelephoneOrder () {// Ni uporabno za spletno naročilo vrzi novo UnsupportedOperationException ()} public void payOnline () {// logika za plačilo online} public void walkInCustomerOrder () {// Ni uporabno za spletno naročilo vrzi novo UnsupportedOperationException ()} javno neveljavno payInPerson () {// ni uporabno za spletno naročilo vrže novo UnsupportedOperationException ()}}
  • Ker je zgornja koda (OnlineClientImpl.java) namenjena spletnim naročilom, vrzite UnsupportedOperationException.

  • Spletni, telefonski in vhodni odjemalci uporabljajo izvedbo RestaurantInterface, specifično za vsakega od njih.

  • Razredi izvajanja za odjemalca Telephonic in odjemalca Walk-in bodo imeli nepodprte metode.

  • Ker je 5 metod del RestaurantInterface, morajo izvedbeni razredi implementirati vseh 5.

  • Metode, ki jih vsak izvedbeni razred vrže UnsupportedOperationException. Kot lahko jasno vidite - izvajanje vseh metod je neučinkovito.

    sas vaja za programiranje za začetnike
  • Kakršna koli sprememba katerega koli od načinov RestaurantInterface bo razširjena na vse izvedbene razrede. Vzdrževanje kode začne potem postajati zares okorno in regresijski učinki sprememb se bodo še povečevali.

  • RestaurantInterface.java krši načelo enotne odgovornosti, ker sta logika za plačila in logika za oddajo naročil združena v en vmesnik.

Da bi odpravili zgoraj omenjene težave, uporabljamo načelo ločevanja vmesnikov, da refaktoriramo zgornjo zasnovo.

  1. Ločite funkcionalnosti plačil in naročil v dva ločena vitka vmesnika, PaymentInterface.java in OrderInterface.java.

  2. Vsaka stranka uporablja po eno izvedbo PaymentInterface in OrderInterface. Na primer - OnlineClient.java uporablja OnlinePaymentImpl in OnlineOrderImpl itd.

  3. Načelo posamezne odgovornosti je zdaj priloženo kot vmesnik za plačilo (PaymentInterface.java) in vmesnik za naročanje (OrderInterface).

  4. Sprememba katerega koli vmesnika za naročilo ali plačilo ne vpliva na drugega. Zdaj so neodvisni. Ne bo vam treba izvajati navidezne implementacije ali vrgati UnsupportedOperationException, saj ima vsak vmesnik samo metode, ki jih bo vedno uporabil.

Po prijavi ISP

Načelo inverzije odvisnosti

Robert C. Martin ga opisuje, saj je odvisen od abstrakcije in ne od betona. Po njegovem se modul na visoki ravni ne sme nikoli zanašati na noben modul na nizki ravni. na primer

Nekaj ​​kupite v lokalni trgovini in se odločite za plačilo z debetno kartico. Ko torej kartico daste uradniku za izvedbo plačila, se uslužbenec ne trudi preveriti, kakšno kartico ste dali.

Tudi če ste dali kartico Visa, on ne bo ugasnil naprave Visa za poteg vaše kartice. Vrsta kreditne ali debetne kartice, ki jo imate za plačilo, sploh ni pomembna, saj jo bodo preprosto povlekli. V tem primeru lahko vidite, da ste vi in ​​uslužbenec odvisni od abstrakcije kreditne kartice in vas ne skrbijo posebnosti kartice. To je tisto, kar je načelo inverzije odvisnosti.

Zakaj je to načelo potrebno?

Programerju omogoča, da odstrani trdo kodirane odvisnosti, tako da postane aplikacija ohlapno povezana in razširljiva.

javni razred študent {zasebni naslov naslov javni študent () {naslov = nov naslov ()}}

V zgornjem primeru razred Student zahteva objekt Address in je odgovoren za inicializacijo in uporabo predmeta Address. Če se v prihodnje spremeni naslovni razred, moramo spremeniti tudi študentski. Tako je tesno povezano med predmetoma Student in Address. To težavo lahko rešimo z vzorcem načrtovanja inverzije odvisnosti. tj. Naslovni objekt bo izveden neodvisno in bo študentu na voljo, ko bo študent instantiran z uporabo inverzije odvisnosti na osnovi konstruktorja ali nastavitve.

S tem smo prišli do konca teh TRDIH načel v Javi.

Oglejte si Edureka, zaupanja vredno podjetje za spletno učenje z mrežo več kot 250.000 zadovoljnih učencev, ki se širijo po vsem svetu. Edurekin tečaj za usposabljanje in certificiranje Java J2EE in SOA je namenjen študentom in strokovnjakom, ki želijo biti razvijalec Java. Tečaj je zasnovan tako, da vam omogoči uvod v programiranje Java in vas usposobi za osnovne in napredne koncepte Java, skupaj z različnimi Java okviri, kot so Hibernate & Spring.

Imate vprašanje za nas? Prosimo, omenite ga v oddelku za komentarje tega spletnega dnevnika „SOLID Principles in Java“, da se vam bomo javili v najkrajšem možnem času.