Princip for et enkelt ansvar i Java

1. Oversigt

I denne vejledning vil vi diskutere Single Responsibility Principle, som et af SOLID-principperne for objektorienteret programmering.

Samlet set vil vi gå i dybden med, hvad dette princip er, og hvordan vi implementerer det, når vi designer vores software. Desuden forklarer vi, hvornår dette princip kan være vildledende.

* SRP = princip om enkelt ansvar

2. Enkelt ansvarsprincip

Som navnet antyder, siger dette princip det hver klasse skulle haveet ansvar, et enkelt formål. Dette betyder, at en klasse kun udfører et job, hvilket får os til at konkludere, at det burde have kun en grund til at ændre sig.

Vi ønsker ikke objekter, der ved for meget og har uafhængig adfærd. Disse klasser er sværere at vedligeholde. For eksempel, hvis vi har en klasse, som vi ændrer meget, og af forskellige årsager, bør denne klasse opdeles i flere klasser, der hver håndterer en enkelt bekymring. Sikkert, hvis der opstår en fejl, vil det være lettere at finde.

Lad os overveje en klasse, der indeholder kode, der ændrer teksten på en eller anden måde. Det eneste job i denne klasse burde være manipulere tekst.

offentlig klasse TextManipulator {privat streng tekst; offentlig TextManipulator (strengtekst) {this.text = tekst; } offentlig String getText () {returtekst; } public void appendText (String newText) {text = text.concat (newText); } public String findWordAndRlace (String word, String replacementWord) {if (text.contains (word)) {text = text.replace (word, replacementWord); } returnere tekst } public String findWordAndDelete (String word) {if (text.contains (word)) {text = text.replace (word, ""); } returnere tekst } offentlig ugyldig printText () {System.out.println (textManipulator.getText ()); }}

Selvom dette kan virke fint, er det ikke et godt eksempel på SRP. Her har vi det toansvar: manipulation og udskrivning af teksten.

At have en metode, der udskriver tekst i denne klasse, er i strid med princippet om et enkelt ansvar. Til dette formål skal vi oprette en anden klasse, der kun håndterer udskrivning af tekst:

offentlig klasse TextPrinter {TextManipulator textManipulator; offentlig TextPrinter (TextManipulator textManipulator) {this.textManipulator = textManipulator; } offentlig ugyldig printText () {System.out.println (textManipulator.getText ()); } offentlig ugyldig printOutEachWordOfText () {System.out.println (Arrays.toString (textManipulator.getText (). split (""))); } public void printRangeOfCharacters (int startingIndex, int endIndex) {System.out.println (textManipulator.getText (). substring (startingIndex, endIndex)); }}

Nu, i denne klasse, kan vi oprette metoder til så mange variationer af udskrivning af tekst, som vi vil, fordi det er dets job.

3. Hvordan kan dette princip misvises?

Tricket med at implementere SRP i vores software er at kende ansvaret af hver klasse.

Imidlertid, hver udvikler har deres vision om klassens formål, hvilket gør tingene vanskelige. Da vi ikke har strenge instruktioner om, hvordan vi implementerer dette princip, står vi tilbage med vores fortolkninger af, hvad ansvaret vil være.

Hvad dette betyder er, at nogle gange kun vi som designere af vores applikation kan bestemme, om noget er inden for en klasse eller ej.

Når vi skriver en klasse i henhold til SRP-princippet, skal vi tænke på problemdomænet, forretningsbehov og applikationsarkitektur. Det er meget subjektivt, hvilket gør implementeringen af ​​dette princip sværere, end det ser ud til. Det vil ikke være så simpelt som eksemplet, vi har i denne vejledning.

Dette fører os til det næste punkt.

4. Samhørighed

Efter SRP-princippet følger vores klasser en funktionalitet. Deres metoder og data vedrører et klart formål. Det betyder høj samhørighed såvel som robusthed, som tilsammen reducerer fejl.

Når vi designer software baseret på SRP-princippet, er samhørighed afgørende, da det hjælper os med at finde et enkelt ansvar for vores klasser. Dette koncept hjælper os også med at finde klasser, der har mere end et ansvar.

Lad os gå tilbage til vores TextManipulator klassemetoder:

... public void appendText (String newText) {text = text.concat (newText); } public String findWordAndRlace (String word, String replacementWord) {if (text.contains (word)) {text = text.replace (word, replacementWord); } returnere tekst } public String findWordAndDelete (String word) {if (text.contains (word)) {text = text.replace (word, ""); } returnere tekst } ...

Her har vi en klar gengivelse af, hvad denne klasse gør: Tekstmanipulation.

Men hvis vi ikke tænker på samhørighed, og vi ikke har en klar definition af, hvad denne klasses ansvar er, kunne vi sige, at skrivning og opdatering af teksten er to forskellige og separate job. Anført af denne tanke kan vi konkludere, at disse burde være to separate klasser: Skriv tekst og UpdateText.

I virkeligheden ville vi få det to klasser, der er tæt koblet og løst sammenhængende, som næsten altid skal bruges sammen. Disse tre metoder kan udføre forskellige operationer, men de tjener i det væsentlige et enkelt formål: Tekstmanipulation. Nøglen er ikke at overtænke.

Et af de værktøjer, der kan hjælpe med at opnå høj samhørighed i metoder, er LCOM. I det væsentlige LCOM måler forbindelsen mellem klassekomponenter og deres relation til hinanden.

Martin Hitz og Behzad Montazeri introducerede LCOM4, ​​som Sonarqube målte et stykke tid, men siden er forældet.

5. Konklusion

Selvom navnet på princippet er selvforklarende, kan vi se, hvor let det er at implementere forkert. Sørg for at skelne mellem hver klasses ansvar, når du udvikler et projekt, og vær opmærksom på samhørighed.

Som altid er koden tilgængelig på GitHub.


$config[zx-auto] not found$config[zx-overlay] not found