Interface-segregatieprincipe in Java

1. Inleiding

In deze tutorial bespreken we het Interface Segregation Principle, een van de SOLID-principes. Interfacescheiding, die de "I" in "SOLID" vertegenwoordigt, betekent eenvoudigweg dat we grotere interfaces in kleinere moeten opsplitsen.

Zodoende wordt gegarandeerd dat implementatieklassen geen ongewenste methoden hoeven te implementeren.

2. Principe van scheiding van interfaces

Dit principe werd voor het eerst gedefinieerd door Robert C. Martin als: "Cliënten moeten niet worden gedwongen afhankelijk te zijn van interfaces die ze niet gebruiken“.

Het doel van dit principe is om verminder de bijwerkingen van het gebruik van grotere interfaces door applicatie-interfaces op te splitsen in kleinere. Het is vergelijkbaar met het Single Responsibility Principle, waarbij elke klasse of interface één doel dient.

Nauwkeurig applicatieontwerp en correcte abstractie is de sleutel achter het Interface Segregation Principle. Hoewel het meer tijd en moeite kost in de ontwerpfase van een applicatie en de codecomplexiteit kan vergroten, krijgen we uiteindelijk een flexibele code.

We zullen enkele voorbeelden bekijken in de latere secties waar we een schending van het principe hebben, en dan zullen we het probleem oplossen door het principe correct toe te passen.

3. Voorbeeldinterface en implementatie

Laten we eens kijken naar een situatie waarin we een Betaling interface gebruikt door een implementatie Bankbetaling:

openbare interface Betaling {void initiatePayments (); Objectstatus (); Lijst getPayments (); }

En de implementatie:

openbare klasse BankPayment implementeert Payment {@Override public void initiatePayments () {// ...} @Override public Object status () {// ...} @Override public List getPayments () {// ...}}

Laten we voor de eenvoud de feitelijke zakelijke implementatie van deze methoden negeren.

Dit is heel duidelijk - tot dusver de uitvoerende klasse Bankbetaling heeft alle methoden in het Betaling koppel. Het is dus niet in strijd met het principe.

4. Vervuiling van de interface

Nu we vooruitgaan in de tijd en er meer functies binnenkomen, is het nodig om een LeningBetaling onderhoud. Deze service is ook een soort van Betaling maar heeft nog een paar operaties.

Om deze nieuwe functie te ontwikkelen, zullen we de nieuwe methoden toevoegen aan het Betaling koppel:

openbare interface Betaling {// originele methoden ... void intiateLoanSettlement (); ongeldig initiateRePayment (); }

Vervolgens hebben we de LeningBetaling implementatie:

openbare klasse LoanPayment implementeert Payment {@Override public void initiatePayments () {throw new UnsupportedOperationException ("Dit is geen bankbetaling"); } @Override public Object status () {// ...} @Override public list getPayments () {// ...} @Override public void intiateLoanSettlement () {// ...} @Override public void initiateRePayment () {// ...}}

Nu, sinds de Betaling interface is veranderd en er zijn meer methoden toegevoegd, alle implementatieklassen moeten nu de nieuwe methoden implementeren. Het probleem is dat de implementatie ervan ongewenst is en tot veel bijwerkingen kan leiden. Hier de LeningBetaling implementatie klasse moet het initiatePayments () zonder dat dit echt nodig is. En dus wordt het principe geschonden.

Dus, wat gebeurt er met onze Bankbetaling klasse:

openbare klasse BankPayment implementeert betaling {@Override public void initiatePayments () {// ...} @Override public Object status () {// ...} @Override openbare lijst getPayments () {// ...} @Override public void intiateLoanSettlement () {throw new UnsupportedOperationException ("Dit is geen leningbetaling"); } @Override public void initiateRePayment () {throw new UnsupportedOperationException ("Dit is geen leningbetaling"); }}

Merk op dat de Bankbetaling implementatie heeft nu de nieuwe methoden geïmplementeerd. En aangezien het ze niet nodig heeft en er geen logica voor heeft, is het dat wel gewoon een UnsupportedOperationException. Dit is waar we het principe beginnen te schenden.

In de volgende sectie zullen we zien hoe we dit probleem kunnen oplossen.

5. Het principe toepassen

In de laatste sectie hebben we opzettelijk de interface vervuild en het principe geschonden. In dit gedeelte bekijken we hoe u de nieuwe functie voor het betalen van leningen kunt toevoegen zonder het principe te schenden.

Laten we de interface voor elk betalingstype opsplitsen. De huidige situatie:

Merk op in het klassendiagram, en verwijzend naar de interfaces in de eerdere sectie, dat het toestand() en getPayments () methoden zijn vereist in beide implementaties. Aan de andere kant, initiatePayments () is alleen vereist in Bankbetaling, en de initiateLoanSettlement () en initiateRePayment () methoden zijn alleen voor de LeningBetaling.

Met dat gesorteerd, laten we de interfaces opsplitsen en het Interface Segregation Principle toepassen. We hebben nu dus een gemeenschappelijke interface:

openbare interface Betaling {Objectstatus (); Lijst getPayments (); }

En nog twee interfaces voor de twee soorten betalingen:

openbare interface Bank verlengt betaling {void initiatePayments (); }
openbare interface Lening verlengt Betaling {void intiateLoanSettlement (); ongeldig initiateRePayment (); }

En de respectievelijke implementaties, te beginnen met Bankbetaling:

openbare klasse BankPayment implementeert Bank {@Override public void initiatePayments () {// ...} @Override public Object status () {// ...} @Override openbare lijst getPayments () {// ...}}

En tot slot, onze herziene LeningBetaling implementatie:

openbare klasse LoanPayment implementeert Lening {@Override public void intiateLoanSettlement () {// ...} @Override public void initiateRePayment () {// ...} @Override public Object status () {// ...} @Override openbare lijst getPayments () {// ...}}

Laten we nu het nieuwe klassendiagram bekijken:

Zoals we kunnen zien, schenden de interfaces het principe niet. De implementaties hoeven geen lege methoden te bieden. Dit houdt de code schoon en verkleint de kans op bugs.

6. Conclusie

In deze tutorial hebben we gekeken naar een eenvoudig scenario, waarbij we eerst afweken van het volgen van het Interface Segregation Principle en zagen welke problemen deze afwijking veroorzaakte. Vervolgens hebben we laten zien hoe we het principe correct kunnen toepassen om deze problemen te vermijden.

Als we te maken hebben met vervuilde oudere interfaces die we niet kunnen wijzigen, kan het adapterpatroon van pas komen.

Het Interface Segregation Principle is een belangrijk concept bij het ontwerpen en ontwikkelen van applicaties. Door dit principe aan te houden, worden opgeblazen interfaces met meerdere verantwoordelijkheden voorkomen. Dit helpt ons uiteindelijk om ook het Single Responsibility Principle te volgen.

Zoals altijd is de code beschikbaar op GitHub.