Načelo segregacije sučelja u Javi

1. Uvod

U ovom uputstvu razgovarat ćemo o načelu segregacije sučelja, jednom od SOLID principa. Predstavljajući "I" u "SOLID", segregacija sučelja jednostavno znači da bismo trebali razbiti veća sučelja na manja.

Tako osiguravajući da provedba klasa ne mora provoditi neželjene metode.

2. Načelo razdvajanja sučelja

Ovo je načelo prvi definirao Robert C. Martin kao: „Klijente ne treba prisiljavati da ovise o sučeljima koja ne koriste“.

Cilj ovog principa je da smanjiti nuspojave korištenja većih sučelja razbijanjem aplikacijskih sučelja na manja. Slično je principu jedinstvene odgovornosti, gdje svaka klasa ili sučelje ima jednu svrhu.

Precizan dizajn aplikacije i ispravna apstrakcija ključ su principa segregacije sučelja. Iako će trebati više vremena i truda u fazi dizajniranja aplikacije i možda će povećati složenost koda, na kraju dobivamo fleksibilni kôd.

U sljedećim ćemo odjeljcima razmotriti neke primjere u kojima imamo kršenje načela, a zatim ćemo riješiti problem ispravnom primjenom načela.

3. Uzorak sučelja i implementacije

Pogledajmo situaciju u kojoj imamo Plaćanje sučelje koje koristi implementacija BankPayment:

javno sučelje Payment {void initiatePayments (); Status objekta (); Popis getPayments (); }

I provedba:

javna klasa BankPayment implementira plaćanje {@Override public void initiatePayments () {// ...} @Override public Object status () {// ...} @Override public List getPayments () {// ...}}

Radi jednostavnosti, zanemarimo stvarnu poslovnu implementaciju ovih metoda.

To je vrlo jasno - do sada, izvedbena klasa BankPayment treba sve metode u Plaćanje sučelje. Dakle, to ne krši načelo.

4. Onečišćenje sučelja

Sada, kako idemo na vrijeme, a sve više značajki dolazi, potrebno je dodati i Isplata zajma servis. Ova je usluga također vrsta Plaćanje ali ima još nekoliko operacija.

Da bismo razvili ovu novu značajku, dodat ćemo nove metode u Plaćanje sučelje:

javno sučelje Plaćanje {// izvorne metode ... void intiateLoanSettlement (); poništi InitiateRePayment (); }

Dalje, imat ćemo Isplata zajma provedba:

javna klasa LoanPayment implementira Payment {@Override public void initiatePayments () {throw new UnsupportedOperationException ("Ovo nije bankovno plaćanje"); } @Override public Object status () {// ...} @Override public List getPayments () {// ...} @Override public void intiateLoanSettlement () {// ...} @Override public void initiateRePayment () {// ...}}

Sad, od Plaćanje sučelje se promijenilo i dodano je više metoda, sve klase implementacije sada moraju implementirati nove metode. Problem je što je njihova primjena neželjena i mogla bi dovesti do mnogih nuspojava. Evo, Isplata zajma klasa implementacije mora implementirati initiatePayments () bez stvarne potrebe za tim. I tako, načelo se krši.

Dakle, što se događa s našim BankPayment razred:

javna klasa BankPayment implementira plaćanje {@Override public void initiatePayments () {// ...} @Override status javnog objekta () {// ...} @Override public List getPayments () {// ...} @Override public void intiateLoanSettlement () {bacanje novog UnsupportedOperationException ("Ovo nije plaćanje zajma"); } @Override public void initiateRePayment () {throw new UnsupportedOperationException ("Ovo nije plaćanje zajma"); }}

Imajte na umu da BankPayment implementacija je sada implementirala nove metode. A budući da ih ne trebaju i nema logike za njih, jest samo bacanje UnsupportedOperationException. Tu počinjemo kršiti načelo.

U sljedećem ćemo odjeljku vidjeti kako možemo riješiti ovaj problem.

5. Primjena principa

U posljednjem smo dijelu namjerno zagađivali sučelje i kršili načelo. U ovom ćemo odjeljku proučiti kako dodati novu značajku za plaćanje zajma bez kršenja načela.

Razlomimo sučelje za svaku vrstu plaćanja. Trenutna situacija:

Primijetite u dijagramu klasa, pozivajući se na sučelja u prethodnom odjeljku, da status() i getPayments () metode su potrebne u obje implementacije. S druge strane, initiatePayments () je potreban samo u BankPayment, i initiateLoanSettlement () i initiateRePayment () metode su samo za Isplata zajma.

S tim razvrstanim, rastavimo sučelja i primijenimo Načelo segregacije sučelja. Dakle, sada imamo zajedničko sučelje:

javno sučelje Plaćanje {Status objekta (); Popis getPayments (); }

I još dva sučelja za dvije vrste plaćanja:

javno sučelje Banka produžuje Payment {void initiatePayments (); }
zajam javnog sučelja proširuje plaćanje {void intiateLoanSettlement (); poništi InitiateRePayment (); }

I odgovarajuće implementacije, počevši od BankPayment:

javna klasa BankPayment implementira banku {@Override public void initiatePayments () {// ...} @Override public Object status () {// ...} @Override public List getPayments () {// ...}}

I na kraju, naša revidirana Isplata zajma provedba:

javna klasa LoanPayment implementira zajam {@Override public void intiateLoanSettlement () {// ...} @Override public void initiateRePayment () {// ...} @Override status javnog objekta () {// ...} @Override javni popis getPayments () {// ...}}

Pogledajmo sada novi dijagram razreda:

Kao što vidimo, sučelja ne krše načelo. Implementacije ne moraju pružati prazne metode. To održava kôd čistim i smanjuje mogućnost bugova.

6. Zaključak

U ovom smo tutorijalu pogledali jednostavan scenarij, gdje smo prvo odstupili od slijeđenja načela segregacije sučelja i vidjeli probleme koje je ovo odstupanje uzrokovalo. Zatim smo pokazali kako pravilno primijeniti načelo kako bismo izbjegli ove probleme.

U slučaju da imamo posla s zagađenim naslijeđenim sučeljima koja ne možemo izmijeniti, uzorak adaptera može dobro doći.

Načelo razdvajanja sučelja važan je koncept tijekom dizajniranja i razvoja aplikacija. Pridržavanje ovog načela pomaže u izbjegavanju napuhanih sučelja s višestrukim odgovornostima. To nam na kraju pomaže da slijedimo i princip jedinstvene odgovornosti.

Kao i uvijek, kôd je dostupan na GitHub-u.