Viss, kas jums jāzina par Java pamatprincipiem



Šajā rakstā jūs uzzināsiet detalizēti par to, kas ir cietie principi java, ar piemēriem un to nozīmi reālajā dzīvē.

Pasaulē (OOP), ir daudz dizaina vadlīniju, modeļu vai principu. Pieci no šiem principiem parasti tiek sagrupēti un ir pazīstami ar akronīmu SOLID. Kaut arī katrs no šiem pieciem principiem apraksta kaut ko konkrētu, tie tikpat labi pārklājas, ka viena no tiem pieņemšana nozīmē vai liek pieņemt citu. Šajā rakstā mēs sapratīsim SOLID principus Java.

SOLID principu vēsture Java

Roberts C. Martins sniedza piecus objektorientēta dizaina principus, un tam tiek izmantots akronīms “S.O.L.I.D”. Ja izmantojat visus S.O.L.I.D principus kombinētā veidā, jums kļūst vieglāk izstrādāt programmatūru, kuru var viegli pārvaldīt. Citas S.O.L.I.D izmantošanas iespējas ir:





  • Tas novērš koda smakas.
  • Ātri refraktora kods.
  • Var veikt adaptīvu vai veiklu programmatūras izstrādi.

Kad kodēšanā izmantojat S.O.L.I.D principu, jūs sākat rakstīt efektīvu un lietderīgu kodu.



Ko nozīmē S.O.L.I.D?

Cietais pārstāv piecus java principus, kas ir:

  • S : Vienotas atbildības princips
  • VAI : Atvērta-slēgta princips
  • L : Liskova aizstāšanas princips
  • Es : Saskarnes nošķiršanas princips
  • D : Atkarības inversijas princips

Šajā emuārā mēs detalizēti apspriedīsim visus piecus Java SOLID principus.



Vienotas atbildības princips Java

Ko tas saka?

Roberts C. Martins to raksturo, ka vienai klasei vajadzētu būt tikai vienīgajai atbildībai.

Saskaņā ar vienas atbildības principu klasei jāmaina tikai viens iemesls. Tas nozīmē, ka klasei ir jāveic viens uzdevums. Šo principu bieži sauc par subjektīvu.

Principu var labi saprast ar piemēru. Iedomājieties, ka ir klase, kas veic šādas darbības.

  • Savienots ar datu bāzi

  • Lasiet dažus datus no datu bāzes tabulām

  • Visbeidzot, ierakstiet to failā.

Vai esat iedomājies scenāriju? Šeit klasei ir vairāki iemesli, lai mainītos, un daži no tiem ir faila izvades modifikācija, jaunas datu bāzes pieņemšana. Kad mēs runājam par viena principa atbildību, mēs teiktu, ka ir pārāk daudz iemeslu, kāpēc klase mainās, tāpēc tas neatbilst pienācīgi vienas atbildības principam.

objektu masīvs java

Piemēram, Automobile klase var sākt vai apturēt sevi, bet tās mazgāšanas uzdevums pieder CarWash klasei. Citā piemērā grāmatu klasei ir īpašības, lai saglabātu savu vārdu un tekstu. Bet grāmatas drukāšanas uzdevumam jāpiedalās grāmatu printeru klasē. Grāmatu printeru klase var drukāt uz konsoles vai cita datu nesēja, taču šādas atkarības no grāmatu klases tiek noņemtas

Kāpēc šis princips ir nepieciešams?

Kad tiek ievērots Vienotās atbildības princips, testēšana ir vienkāršāka. Ar vienu atbildību klasē būs mazāk pārbaudes gadījumu. Mazāka funkcionalitāte nozīmē arī mazāku atkarību no citām klasēm. Tas ļauj labāk organizēt kodu, jo mazākas un labi domātas klases ir vieglāk meklēt.

Piemērs šī principa precizēšanai:

Pieņemsim, ka jums tiek lūgts ieviest pakalpojumu UserSetting, kurā lietotājs var mainīt iestatījumus, bet pirms tam lietotājs ir autentificēts. Viens no veidiem, kā to īstenot, būtu:

public class UserSettingService {public void changeEmail (User user) {if (checkAccess (user)) {// Piešķirt iespēju mainīt}} public boolean checkAccess (User user) {// Pārbaudiet, vai lietotājs ir derīgs. }}

Viss izskatās labi līdz brīdim, kad vēlaties atkārtoti izmantot checkAccess kodu kādā citā vietā, VAI vēlaties mainīt checkAccess darbības veidu. Visos divos gadījumos jūs galu galā mainīsit to pašu klasi, un pirmajā gadījumā jums būs jāizmanto UserSettingService, lai pārbaudītu arī piekļuvi.
Viens no veidiem, kā to labot, ir sadalīt UserSettingService par UserSettingService un SecurityService. Un pārvietojiet checkAccess kodu uz SecurityService.

public class UserSettingService {public void changeEmail (User user) {if (SecurityService.checkAccess (user)) {// Piešķirt iespēju mainīt}}} public class SecurityService {public static Boolean checkAccess (User user) {// pārbaudiet piekļuvi. }}

Java atvērtais slēgtais princips

Roberts C. Martins to raksturo kā programmatūras komponentiem jābūt atvērtiem paplašināšanai, bet slēgtiem modifikācijām.

Precīzāk sakot, saskaņā ar šo principu klase jāraksta tā, lai tā savu darbu veiktu nevainojami, nepieņemot, ka nākotnē cilvēki vienkārši nāks un to mainīs. Tādējādi klasei jāpaliek slēgtai modifikāciju veikšanai, taču tai vajadzētu būt iespējai pagarināt. Klases pagarināšanas veidi ietver:

  • Mantojot no klases

  • Nepieciešamās uzvedības pārrakstīšana no klases

  • Noteiktas klases uzvedības paplašināšana

Lielisku atvērta un slēgta principa piemēru var saprast ar pārlūkprogrammu palīdzību. Vai atceraties paplašinājumu instalēšanu savā Chrome pārlūkprogrammā?

Hroma pārlūka pamatfunkcija ir sērfošana dažādās vietnēs. Vai vēlaties pārbaudīt gramatiku, rakstot e-pastu, izmantojot Chrome pārlūku? Ja jā, varat vienkārši izmantot paplašinājumu Grammarly, tas nodrošina satura gramatikas pārbaudi.

Šis mehānisms, kurā pievienojat lietas pārlūka funkcionalitātes palielināšanai, ir paplašinājums. Tādējādi pārlūkprogramma ir lielisks piemērs funkcionalitātei, kas ir atvērta paplašināšanai, bet ir slēgta modifikācijai. Vienkārši sakot, jūs varat uzlabot funkcionalitāti, pievienojot / instalējot spraudņus savā pārlūkprogrammā, taču nevarat izveidot neko jaunu.

Kāpēc šis princips ir vajadzīgs?

OCP ir svarīga, jo nodarbības pie mums var nākt, izmantojot trešo pušu bibliotēkas. Mums vajadzētu būt iespējai pagarināt šīs klases, neuztraucoties, vai šīs bāzes klases var atbalstīt mūsu paplašinājumus. Bet mantošana var izraisīt apakšklases, kas ir atkarīgas no pamatklases ieviešanas. Lai no tā izvairītos, ieteicams izmantot saskarnes. Šī papildu abstrakcija noved pie vaļīgas sakabes.

Pieņemsim, ka mums jāaprēķina dažādu formu laukumi. Mēs sākam ar klases izveidošanu mūsu pirmajai formai Taisnstūriskurai ir 2 atribūtu garums& platums.

public class Taisnstūris {public double length public double width}

Tālāk mēs izveidojam klasi, lai aprēķinātu šī taisnstūra laukumukurai ir metode aprēķinātTaisnstūra platībakas ņem Taisnstūrikā ievades parametru un aprēķina tā laukumu.

public class AreaCalculator {public double aprēķinātRectangleArea (Taisnstūra taisnstūris) {return rectangle.length * rectangle.width}}

Tik tālu, labi. Pieņemsim, ka mēs iegūstam savu otro formas apli. Tāpēc mēs nekavējoties izveidojam jaunu klases lokuar vienu atribūta rādiusu.

public class Circle {public double radius}

Tad mēs modificējam apgabala kalkulatoruklase, lai pievienotu apļa aprēķinus, izmantojot jaunu metodi aprēķinātCircleaArea ()

public class AreaCalculator {public double aprēķinātRectangleArea (Taisnstūra taisnstūris) {return taisnstūris.length * taisnstūris.platums} public double

Tomēr ņemiet vērā, ka mūsu risinājuma izstrādē iepriekš bija trūkumi.

Pieņemsim, ka mums ir jauns formas piecstūris. Tādā gadījumā mēs atkal nonāksim pie AreaCalculator klases pārveidošanas. Pieaugot figūru tipiem, tas kļūst arvien īsāks, jo AreaCalculator turpina mainīties, un visiem šīs klases patērētājiem būs jāturpina atjaunināt savas bibliotēkas, kurās ir AreaCalculator. Tā rezultātā AreaCalculator klase netiks pamatota (pabeigta) ar galvojumu, jo katru reizi, kad nāk jauna forma, tā tiks modificēta. Tātad, šis dizains nav slēgts modifikācijai.

AreaCalculator būs jāturpina pievienot sava skaitļošanas loģika jaunākās metodēs. Mēs īsti nepaplašinām formu loku, bet mēs vienkārši darām gabaliņu miltu (bit-by-bit) risinājumu katrai pievienotajai formai.

Iepriekš minētā dizaina pārveidošana, lai tas atbilstu atvērta / slēgta principam:

Tagad redzēsim elegantāku dizainu, kas novērš iepriekš minētā dizaina trūkumus, ievērojot atvērto / slēgto principu. Mēs vispirms padarīsim dizainu paplašināmu. Lai to izdarītu, mums vispirms ir jādefinē bāzes veida forma un ir jābūt Circle & Taisnstūra formas saskarnei.

publiskā saskarne Forma {public double aprēķinātArea ()} publiskā klase Taisnstūris īsteno Shape {dubultā garums dubultplatums public double aprēķina apgabals () {atgriešanās garums * platums}} public class Aplis ievieš forma {public double rādiuss public double aprēķinaapgabals () {return (22 / 7) * rādiuss * rādiuss}}

Ir bāzes saskarnes forma. Visas formas tagad ievieš bāzes saskarnes formu. Formas saskarnei ir abstrakta metode calcArea (). Gan aplis, gan taisnstūris nodrošina viņu pašu ignorēto metodes calcArea () ieviešanu, izmantojot savus atribūtus.
Mēs esam ieviesuši zināmu paplašināmības pakāpi, jo formas tagad ir formas saskarnes piemērs. Tas ļauj mums izmantot formu atsevišķu klašu vietā
Pēdējais iepriekš minētais punkts minēja šo formu patērētāju. Mūsu gadījumā patērētājs būs klase AreaCalculator, kas tagad izskatīsies šādi.

public class AreaCalculator {public double aprēķinātShapeArea (formas forma) {return shape.calculateArea ()}}

Šis apgabala kalkulatorsklase tagad pilnībā novērš mūsu iepriekš minētos dizaina trūkumus un sniedz tīru risinājumu, kas atbilst atvērta-slēgta principam. Pārejam pie citiem SOLID principiem Java

Liskova aizstāšanas princips Java valodā

Roberts C. Martins to raksturo kā atvasinātos tipus, kas ir pilnībā aizstājami ar to bāzes tipiem.

Liskova aizstāšanas princips pieņem, ka q (x) ir īpašums, ko var pierādīt attiecībā uz x tipam piederošām entītijām, kas pieder pie T tipa. Tagad saskaņā ar šo principu q (y) tagad vajadzētu būt pierādāmam objektiem y, kas pieder S tipam, un S faktiski ir T. apakštips. Vai jūs tagad esat apmulsis un nezināt, ko patiesībā nozīmē Liskova aizstāšanas princips? Tā definīcija varētu būt nedaudz sarežģīta, bet patiesībā tā ir diezgan vienkārša. Vienīgais ir tas, ka katrai apakšklasei vai atvasinātajai klasei jābūt aizstājamai ar vecāku vai pamatklasi.

Jūs varat teikt, ka tas ir unikāls objektorientēts princips. Principu var vēl vairāk vienkāršot ar konkrēta vecāka tipa bērnu tipu, neradot nekādas komplikācijas vai nespridzinot lietas, vajadzētu būt iespējai iestāties par šo vecāku. Šis princips ir cieši saistīts ar Liskova aizstāšanas principu.

Kāpēc šis princips ir vajadzīgs?

Tas ļauj izvairīties no mantojuma nepareizas izmantošanas. Tas mums palīdz pielāgoties “ir-a” attiecībām. Mēs varam arī teikt, ka apakšklasēm ir jāpilda līgums, ko nosaka bāzes klase. Šajā ziņā tas ir saistīts arProjektēšana pēc līgumato pirmo reizi aprakstīja Bertrands Mejers. Piemēram, ir vilinoši teikt, ka aplis ir elipses veids, bet lokiem nav divu fokusu vai galveno / mazāko asi.

LSP ir populāri izskaidrots, izmantojot kvadrāta un taisnstūra piemēru. ja pieņemam ISA attiecības starp Square un Taisnstūri. Tādējādi mēs saucam “Kvadrāts ir taisnstūris”. Zemāk redzamais kods apzīmē attiecības.

public class Taisnstūris {private int length private int width 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}}

Zemāk ir laukuma kods. Ņemiet vērā, ka Square paplašina taisnstūri.

atšķirība starp galīgo un galīgo
publiskās klases laukums paplašinās taisnstūris {public void setBreadth (int widthth) {super.setBreadth (width) super.setLength (width)} public void setLength (int length) {super.setLength (length) super.setBreadth (length)}}

Šajā gadījumā mēs cenšamies nodibināt ISA attiecības starp Square un Taisnstūri tā, lai izsauktu “Square is a Tectangle” zemāk esošajā kodā sāktu negaidīti izturēties, ja tiktu nodots Square gadījums. Apgalvojuma kļūda tiks izmesta gadījumā, ja pārbaudīsit “Platību” un pārbaudīsit “Platumu”, lai gan programma tiks pārtraukta, jo Apgalvojuma kļūda tiek izmesta apgabala pārbaudes neveiksmes dēļ.

public class LSPDemo {public void aprēķina apgabals (taisnstūris r) {r.setBreadth (2) r.setLength (3) apgalvo r.getArea () == 6: printError ('area', r) apgalvo r.getLength () == 3: printError ('length', r) apgalvo r.getBreadth () == 2: printError ('width', r)} private String printError (String errorIdentifer, Rectangle r) {return 'Negaidīta' + errorIdentifer + 'vērtība piemēram, '+ r.getClass (). getName ()} public static void main (String [] args) {LSPDemo lsp = new LSPDemo () // Taisnstūra eksemplārs tiek nodots lsp.calculateArea (jauns taisnstūris ()) // Laukuma eksemplārs ir nodots lsp.calculateArea (new Square ())}}

Klase demonstrē Liskovas aizstāšanas principu (LSP) Saskaņā ar principu funkcijām, kas izmanto atsauces uz pamatklasēm, jāspēj izmantot atvasinātās klases objektus, to nezinot.

Tādējādi zemāk parādītajā piemērā funkcijai calcArea, kas izmanto atsauci uz “Taisnstūri”, jāspēj izmantot atvasinātas klases objektus, piemēram, Square, un jāatbilst taisnstūra definīcijas izvirzītajām prasībām. Jāņem vērā, ka saskaņā ar taisnstūra definīciju šādiem datiem vienmēr ir jāatbilst patiesībai, ņemot vērā zemāk esošos datus:

  1. Garumam vienmēr jābūt vienādam ar garumu, kas nodots kā ievade metodei setLength
  2. Platumam vienmēr jābūt vienādam ar platumu, kas nodots kā ievade metodei, setBreadth
  3. Platībai vienmēr jābūt vienādai ar garuma un platuma reizinājumu

Gadījumā, ja mēs mēģinām izveidot ISA attiecības starp Kvadrātu un Taisnstūri, lai mēs to saucam par 'Kvadrāts ir taisnstūris', iepriekšējais kods sāktu negaidīti izturēties, ja tiek nodots kvadrāta gadījums. Apgabala kļūda tiks izmesta, pārbaudot laukumu un pārbaudot lai gan programma tiks pārtraukta, jo apgalvojuma kļūda tiek izmesta apgabala pārbaudes neveiksmes dēļ.

Klasei Square nav nepieciešamas tādas metodes kā setBreadth vai setLength. LSPDemo klasei būtu jāzina informācija par taisnstūra atvasinātajām klasēm (piemēram, Square), lai pareizi kodētu, lai izvairītos no metiena kļūdām. Esošā koda maiņa, pirmkārt, pārkāpj atvērta-slēgta principu.

Saskarnes nodalīšanas princips

Roberts C. Martins to raksturo kā klientu nevajadzētu piespiest ieviest nevajadzīgas metodes, kuras viņi neizmantos.

PēcSaskarnes nošķiršanas principsklients, neatkarīgi no tā, ko nekad nevajadzētu piespiest ieviest saskarni, kuru tas neizmanto, vai arī klientam nekad nav pienākums būt atkarīgam no jebkuras metodes, kuru viņi neizmanto. Tātad būtībā saskarnes nošķiršanas principi, kā vēlaties saskarnes, kas ir mazas, bet specifiskas klientam, nevis monolītai un lielākai saskarnei. Īsāk sakot, jums būtu slikti piespiest klientu būt atkarīgam no noteiktas lietas, kas viņiem nav nepieciešama.

Piemēram, viena reģistrēšanas saskarne žurnālu rakstīšanai un lasīšanai ir noderīga datu bāzei, bet ne konsolei. Žurnālu lasīšana konsoles reģistrētājam nav jēgas. Turpinot šo SOLID principu rakstu Java.

Kāpēc šis princips ir vajadzīgs?

Pieņemsim, ka ir restorāna saskarne, kurā ir norādītas metodes, kā pieņemt pasūtījumus no tiešsaistes klientiem, klientiem, kuriem ir iezvanpieejas vai tālruņa numuri, kā arī klientiem, kuri darbojas tiešsaistē. Tas satur arī metodes, kā rīkoties ar tiešsaistes maksājumiem (klientiem tiešsaistē) un personīgajiem maksājumiem (klientiem, kuri veic ienākšanu, kā arī tālruņa klientiem, kad viņu pasūtījums tiek piegādāts mājās).

Tagad ļaujiet mums izveidot Java saskarni restorānam un nosaukt to kā RestaurantInterface.java.

publiskā saskarne RestaurantInterface {public void acceptOnlineOrder () public void takeTelephoneOrder () public void payOnline () public void walkInCustomerOrder () public void payInPerson ()}

Restorāna interfeisā ir noteiktas 5 metodes, kas paredz tiešsaistes pasūtījumu pieņemšanu, tālruņa pasūtījumu pieņemšanu, pasūtījumu pieņemšanu no klienta, tiešsaistes maksājuma pieņemšanu un maksājuma pieņemšanu personīgi.

Sāksim, ieviešot tiešsaistes klientiem RestaurantInterface kā OnlineClientImpl.java

publiskā klase OnlineClientImpl īsteno RestaurantInterface {public void acceptOnlineOrder () {// tiešsaistes pasūtījuma veikšanas loģika} public void takeTelephoneOrder () {// Nav piemērojams tiešsaistes pasūtījumam. mest jaunu UnsupportedOperationException ()} public void payOnline () {// maksāšanas loģika online} public void walkInCustomerOrder () {// Nav piemērojams tiešsaistes pasūtījumam, lai izveidotu jaunu UnsupportedOperationException ()} public void payInPerson () {// Nav piemērojams tiešsaistes pasūtījumam. mest jaunu UnsupportedOperationException ()}}
  • Tā kā iepriekš minētais kods (OnlineClientImpl.java) ir paredzēts tiešsaistes pasūtījumiem, izmetiet UnsupportedOperationException.

  • Tiešsaistes, telefoniski un klienti, kas izmanto klientu, izmanto katram no tiem raksturīgo RestaurantInterface ieviešanu.

  • Telephonic klienta un Walk-in klienta ieviešanas klasēs būs neatbalstītas metodes.

  • Tā kā 5 metodes ir daļa no RestaurantInterface, ieviešanas klasēm ir jāievieš visas 5 no tām.

  • Metodes, kuras katra no ieviešanas klasēm iemet UnsupportedOperationException. Kā jūs skaidri redzat - visu metožu ieviešana ir neefektīva.

  • Jebkuras izmaiņas jebkurā RestaurantInterface metodē tiks izplatītas visās ieviešanas klasēs. Pēc tam koda uzturēšana sāk kļūt ļoti apgrūtinoša, un izmaiņu regresijas ietekme turpinās pieaugt.

  • RestaurantInterface.java pārkāpj vienas atbildības principu, jo maksājumu loģika, kā arī pasūtījumu izvietošanas loģika ir sagrupēta vienā saskarnē.

Lai pārvarētu iepriekš minētās problēmas, mēs izmantojam saskarnes segregācijas principu, lai pārveidotu iepriekš minēto dizainu.

  1. Atdaliet maksājumu un pasūtījumu izvietošanas funkcijas divās atsevišķās liesās saskarnēs - PaymentInterface.java un OrderInterface.java.

  2. Katrs no klientiem izmanto vienu PaymentInterface un OrderInterface ieviešanu. Piemēram - OnlineClient.java izmanto OnlinePaymentImpl un OnlineOrderImpl un tā tālāk.

  3. Vienotās atbildības princips tagad ir pievienots kā maksājumu saskarne (PaymentInterface.java) un pasūtīšanas saskarne (OrderInterface).

  4. Izmaiņas kādā no pasūtījuma vai maksājuma saskarnēm neietekmē otru. Tagad viņi ir neatkarīgi. Nevajadzēs veikt nevienu fiktīvu ieviešanu vai mest UnsupportedOperationException, jo katrā saskarnē ir tikai metodes, kuras tā vienmēr izmantos.

Pēc ISP piemērošanas

Atkarības inversijas princips

Roberts C. Martins to raksturo, jo tas ir atkarīgs no abstrakcijām, nevis no konkretizācijām. Saskaņā ar to augsta līmeņa modulis nekad nedrīkst paļauties uz nevienu zema līmeņa moduli. piemēram

Jūs dodaties uz vietējo veikalu, lai kaut ko nopirktu, un jūs nolemjat par to maksāt, izmantojot savu debetkarti. Tātad, kad jūs nododat karti ierēdnim maksājuma veikšanai, ierēdnis neuztraucas pārbaudīt, kādu karti esat devis.

Pat ja esat iedevis Visa karti, viņš neizliks Visa mašīnu par kartes vilkšanu. Kredītkartes vai debetkartes veids, kas jums jāmaksā, pat nav svarīgi, viņi to vienkārši pārvelk. Tātad šajā piemērā jūs varat redzēt, ka gan jūs, gan ierēdnis esat atkarīgs no kredītkartes ieguves un jūs neuztraucat kartes īpatnības. Tas ir atkarības inversijas princips.

Kāpēc šis princips ir vajadzīgs?

Tas ļauj programmētājam noņemt kodētas atkarības, lai lietojumprogramma kļūtu brīvi savienota un paplašināma.

publiskā klase Skolēns {privātās adreses adrese publiskais Skolēns () {adrese = jauna adrese ()}}

Iepriekš minētajā piemērā studentu klasei ir nepieciešams objekts Adrese, un tā ir atbildīga par objekta Adrese inicializēšanu un izmantošanu. Ja adreses klase tiks mainīta nākotnē, mums jāveic izmaiņas arī studentu klasē. Tas nodrošina studentu un adrešu objektu sasaisti. Mēs varam atrisināt šo problēmu, izmantojot atkarības inversijas noformējuma modeli. i., adreses objekts tiks ieviests neatkarīgi un tiks izsniegts Studentam, kad students tiks instancēts, izmantojot uz konstruktoru vai iestatītāju balstītu atkarības inversiju.

Līdz ar to mēs esam nonākuši pie šiem SOLID principiem Java.

Pārbaudiet Autors: Edureka, uzticams tiešsaistes mācību uzņēmums ar vairāk nekā 250 000 apmierinātu izglītojamo tīklu visā pasaulē. Edureka Java J2EE un SOA apmācības un sertifikācijas kurss ir paredzēts studentiem un profesionāļiem, kuri vēlas būt Java izstrādātāji. Kurss ir paredzēts, lai dotu jums sākumu Java programmēšanā un apmācītu gan Java, gan uzlabotas koncepcijas, kā arī dažādas Java struktūras, piemēram, Hibernate & Spring.

Vai mums ir jautājums? Lūdzu, pieminējiet to šī emuāra “SOLID principi Java” komentāru sadaļā, un mēs sazināsimies ar jums pēc iespējas ātrāk.

apakšvirkne SQL servera piemēros