Sådan udskiftes mange, hvis udsagn i Java

1. Oversigt

Beslutningskonstruktioner er en vigtig del af ethvert programmeringssprog. Men vi lander ved kodning af et stort antal indlejrede hvis udsagn, der gør vores kode mere kompleks og vanskelig at vedligeholde.

I denne vejledning går vi gennem forskellige måder at erstatte indlejrede if-udsagn på.

Lad os undersøge forskellige muligheder, hvordan vi kan forenkle koden.

2. Casestudie

Ofte støder vi på en forretningslogik, der involverer mange forhold, og hver af dem har brug for forskellige behandlinger. Af hensyn til en demo, lad os tage eksemplet med en Lommeregner klasse. Vi har en metode, der tager to tal og en operator som input og returnerer resultatet baseret på operationen:

offentlig int beregne (int a, int b, String operator) {int result = Integer.MIN_VALUE; hvis ("tilføj" .equals (operator)) {result = a + b; } ellers hvis ("multiplicer" .equals (operator)) {result = a * b; } ellers hvis ("divider" .equals (operator)) {result = a / b; } ellers hvis ("træk" .equals (operator)) {result = a - b; } returnere resultat }

Vi kan også implementere dette ved hjælp af kontakt udsagn:

offentlig int beregneUsingSwitch (int a, int b, String operator) {switch (operator) {case "add": result = a + b; pause; // andre sager} returnerer resultat; }

I typisk udvikling, hvis udsagnene kan blive meget større og mere komplekse. Også, switch-sætningerne passer ikke godt, når der er komplekse forhold.

En anden bivirkning ved at have indlejrede beslutningskonstruktioner er, at de bliver uhåndterbare. For eksempel, hvis vi har brug for at tilføje en ny operatør, skal vi tilføje en ny if-erklæring og implementere operationen.

3. Refactoring

Lad os undersøge de alternative muligheder for at erstatte komplekset, hvis udsagn ovenfor til meget enklere og håndterbar kode.

3.1. Fabriksklasse

Mange gange støder vi på beslutningskonstruktioner, der ender med at udføre den samme operation i hver gren. Dette giver mulighed for udtræk en fabriksmetode, der returnerer et objekt af en given type og udfører operationen baseret på den konkrete genstandsadfærd.

Lad os for vores eksempel definere en Operation interface, som har en enkelt ansøge metode:

offentlig grænseflade Operation {int gælder (int a, int b); }

Metoden tager to tal som input og returnerer resultatet. Lad os definere en klasse til udførelse af tilføjelser:

public class Addition implementerer Operation {@Override public int anvend (int a, int b) {return a + b; }}

Vi implementerer nu en fabriksklasse, der returnerer forekomster af Operation baseret på den givne operatør:

offentlig klasse OperatorFactory {statisk kort operationMap = ny HashMap (); statisk {operationMap.put ("tilføj", ny tilføjelse ()); operationMap.put ("divide", ny division ()); // flere operatører} offentlig statisk Valgfri getOperation (strengoperatør) {return Optional.ofNullable (operationMap.get (operator)); }}

Nu, i Lommeregner klasse, kan vi spørge fabrikken for at få den relevante operation og anvende på kildenumrene:

public int calcuUsingFactory (int a, int b, String operator) {Operation targetOperation = OperatorFactory .getOperation (operator) .orElseThrow (() -> new IllegalArgumentException ("Invalid Operator")); return targetOperation.apply (a, b); }

I dette eksempel har vi set, hvordan ansvaret delegeres til løst koblede objekter, der betjenes af en fabriksklasse. Men der kunne være chancer, hvor de indlejrede, hvis udsagn simpelthen flyttes til fabriksklassen, der besejrer vores formål.

Alternativt vi kan opretholde et lager af objekter i en Kort som kunne forespørges for en hurtig opslag. Som vi har set OperatorFactory # operationMap tjener vores formål. Vi kan også initialisere Kort ved kørsel og konfigurer dem til opslag.

3.2. Brug af Enums

Ud over brugen af Kort, vi kan også bruge Enum at mærke en bestemt forretningslogik. Derefter kan vi bruge dem enten i det indlejrede hvis udsagn eller skifte sagudsagn. Alternativt kan vi også bruge dem som en fabrik af objekter og strategisere dem for at udføre den relaterede forretningslogik.

Det ville reducere antallet af indlejrede, hvis udsagn også og delegere ansvaret til den enkelte Enum værdier.

Lad os se, hvordan vi kan opnå det. Først skal vi definere vores Enum:

public enum Operator {ADD, MULTIPLY, SUBTRACT, DIVIDE}

Som vi kan se, er værdierne etiketter for de forskellige operatorer, som vil blive brugt yderligere til beregning. Vi har altid en mulighed for at bruge værdierne som forskellige betingelser i indlejrede hvis udsagn eller skifte sager, men lad os designe en alternativ måde at delegere logikken til Enum sig selv.

Vi definerer metoder til hver af Enum værdier og udfør beregningen. For eksempel:

TILFØJ {@Override public int Apply (int a, int b) {return a + b; }}, // andre operatører offentlig abstrakt int anvender (int a, int b);

Og så i Lommeregner klasse kan vi definere en metode til at udføre operationen:

offentlig int beregne (int a, int b, Operator operator) {return operator.apply (a, b); }

Nu kan vi påberåbe sig metoden ved at konvertere Snor værdi til Operatør ved hjælp af Operatør # valueOf () metode:

@Test offentligt ugyldigt nårCalculateUsingEnumOperator_thenReturnCorrectResult () {Calculator calculator = new Calculator (); int resultat = calculator.calculate (3, 4, Operator.valueOf ("ADD")); assertEquals (7, resultat); }

3.3. Kommandomønster

I den foregående diskussion har vi set brugen af ​​fabriksklasse til at returnere forekomsten af ​​det korrekte forretningsobjekt til den givne operatør. Senere bruges forretningsobjektet til at udføre beregningen i Lommeregner.

Vi kan også designe en lommeregner # beregne metode til at acceptere en kommando, der kan udføres på indgangene. Dette vil være en anden måde at erstatte indlejret på hvis udsagn.

Vi definerer først vores Kommando grænseflade:

offentlig grænseflade Command {Integer execute (); }

Lad os derefter implementere en Tilføj kommando:

offentlig klasse AddCommand implementerer Command {// Instansvariabler public AddCommand (int a, int b) {this.a = a; this.b = b; } @ Override public Integer execute () {return a + b; }}

Lad os endelig introducere en ny metode i Lommeregner som accepterer og udfører Kommando:

offentlig int beregne (Kommando kommando) {return kommando. udfør (); }

Dernæst kan vi påberåbe beregningen ved at starte en Tilføj kommando og send det til Lommeregner # beregne metode:

@Test offentligt ugyldigt nårCalculateUsingCommand_thenReturnCorrectResult () {Calculator calculator = new Calculator (); int resultat = calculator.calculate (ny AddCommand (3, 7)); assertEquals (10, resultat); }

3.4. Regelmotor

Når vi ender med at skrive et stort antal indlejrede if-udsagn, viser hver af betingelserne en forretningsregel, der skal evalueres for at den korrekte logik skal behandles. En regelmotor tager sådan kompleksitet ud af hovedkoden. EN Regelmotor evaluerer Regler og returnerer resultatet baseret på input.

Lad os gå igennem et eksempel ved at designe et simpelt Regelmotor der behandler en Udtryk gennem et sæt af Regler og returnerer resultatet fra det valgte Herske. Først definerer vi en Herske grænseflade:

offentlig grænseflade Regel {boolsk evaluering (udtryk udtryk); Resultat getResult (); }

For det andet, lad os implementere en Regelmotor:

public class RuleEngine {private static List rules = new ArrayList (); statisk {regler.add (ny AddRule ()); } offentlig resultatproces (ekspressionsudtryk) {regelregel = regler .stream () .filter (r -> r.evaluate (expression)) .findFirst () .orElseThrow (() -> new IllegalArgumentException ("Expression matcher ikke nogen Herske")); return rule.getResult (); }}

Det Regelmotor accepterer en Udtryk objekt og returnerer Resultat. Nu, lad os designe Udtryk klasse som en gruppe på to Heltal genstande med Operatør som vil blive anvendt:

offentlig klasse udtryk {privat heltal x; privat heltal y; privat operatør; }

Og endelig lad os definere en brugerdefineret AddRule klasse, der kun vurderer, når TILFØJ operation er specificeret:

offentlig klasse AddRule implementerer regel {@Override offentlig boolsk evaluering (ekspressionsudtryk) {boolsk evalResult = falsk; hvis (expression.getOperator () == Operator.ADD) {this.result = expression.getX () + expression.getY (); evalResult = sandt; } returner evalResult; }}

Vi påberåber os nu Regelmotor med en Udtryk:

@Test offentlig ugyldig nårNumbersGivenToRuleEngine_thenReturnCorrectResult () {Expression expression = new Expression (5, 5, Operator.ADD); RuleEngine motor = ny RuleEngine (); Resultat resultat = engine.process (udtryk); assertNotNull (resultat); assertEquals (10, result.getValue ()); }

4. Konklusion

I denne vejledning undersøgte vi en række forskellige muligheder for at forenkle kompleks kode. Vi lærte også, hvordan man erstatter indlejrede hvis udsagn ved brug af effektive designmønstre.

Som altid kan vi finde den komplette kildekode over GitHub-arkivet.