Hvordan erstatte mange hvis uttalelser i Java

1. Oversikt

Beslutningskonstruksjoner er en viktig del av ethvert programmeringsspråk. Men vi lander i koding av et stort antall nestede hvis uttalelser som gjør koden vår mer kompleks og vanskelig å vedlikeholde.

I denne opplæringen går vi gjennom forskjellige måter å erstatte nestede if-utsagn på.

La oss utforske forskjellige alternativer hvordan vi kan forenkle koden.

2. Sakstudie

Ofte støter vi på en forretningslogikk som innebærer mange forhold, og hver av dem trenger forskjellig behandling. Av hensyn til en demo, la oss ta eksemplet på en Kalkulator klasse. Vi vil ha en metode som tar to tall og en operator som input og returnerer resultatet basert på operasjonen:

offentlig int beregne (int a, int b, String operator) {int result = Integer.MIN_VALUE; if ("add" .equals (operator)) {result = a + b; } annet hvis ("multipliser" .equals (operator)) {result = a * b; } annet hvis ("divide" .equals (operator)) {result = a / b; } annet hvis ("subtrahere" .equals (operator)) {result = a - b; } returnere resultat; }

Vi kan også implementere dette ved hjelp av bytte om uttalelser:

public int calcuUsingSwitch (int a, int b, String operator) {switch (operator) {case "add": result = a + b; gå i stykker; // andre saker} returnerer resultat; }

I typisk utvikling, hvis uttalelsene kan vokse seg mye større og mer komplekse. Også, bryteruttalelsene passer ikke bra når det er komplekse forhold.

En annen bivirkning av å ha nestede beslutningskonstruksjoner er at de blir uhåndterbare. For eksempel, hvis vi trenger å legge til en ny operatør, må vi legge til en ny if-setning og implementere operasjonen.

3. Refactoring

La oss utforske de alternative alternativene for å erstatte det komplekse hvis utsagnene ovenfor til mye enklere og håndterbar kode.

3.1. Fabrikklasse

Mange ganger møter vi beslutningskonstruksjoner som ender med å gjøre den samme operasjonen i hver gren. Dette gir en mulighet til trekke ut en fabrikkmetode som returnerer et objekt av en gitt type og utfører operasjonen basert på den konkrete gjenstandens oppførsel.

For vårt eksempel, la oss definere en Operasjon grensesnitt som har en enkelt søke om metode:

offentlig grensesnitt Operasjon {int gjelder (int a, int b); }

Metoden tar to tall som input og returnerer resultatet. La oss definere en klasse for å utføre tillegg:

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

Vi implementerer nå en fabrikklasse som returnerer forekomster av Operasjon basert på den gitte operatøren:

offentlig klasse OperatorFactory {statisk kart operationMap = ny HashMap (); statisk {operationMap.put ("legg til", ny tillegg ()); operationMap.put ("divide", new Division ()); // flere operatører} offentlig statisk Valgfri getOperation (strengoperatør) {retur Optional.ofNullable (operationMap.get (operator)); }}

Nå, i Kalkulator klasse, kan vi spørre fabrikken for å få den aktuelle operasjonen og bruke 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 eksemplet har vi sett hvordan ansvaret delegeres til løst koblede gjenstander servert av en fabriksklasse. Men det kan være sjanser der de nestede hvis uttalelser rett og slett flyttes til fabrikklassen som beseirer vårt formål.

Alternativt vi kan opprettholde et lager av objekter i en Kart som kan spørres for en rask oppslag. Som vi har sett OperatorFactory # operationMap tjener vårt formål. Vi kan også initialisere Kart ved kjøretid og konfigurer dem for oppslag.

3.2. Bruk av Enums

I tillegg til bruk av Kart, vi kan også bruke Enum å merke bestemt forretningslogikk. Etter det kan vi bruke dem enten i nestet hvis uttalelser eller bryterveskeuttalelser. Alternativt kan vi også bruke dem som en fabrikk med objekter og strategisere dem for å utføre den relaterte forretningslogikken.

Det vil redusere antall nestede hvis uttalelser også og delegere ansvaret til den enkelte Enum verdier.

La oss se hvordan vi kan oppnå det. Først må vi definere vår Enum:

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

Som vi kan observere, er verdiene etikettene til de forskjellige operatørene som skal brukes videre til beregning. Vi har alltid et alternativ å bruke verdiene som forskjellige forhold i nestede hvis utsagn eller bytte tilfeller, men la oss designe en alternativ måte å delegere logikken til Enum seg selv.

Vi definerer metoder for hver av Enum verdier og gjør beregningen. For eksempel:

LEGG TIL {@Override public int gjelder (int a, int b) {return a + b; }}, // andre operatører offentlig abstrakt int gjelder (int a, int b);

Og så i Kalkulator klasse kan vi definere en metode for å utføre operasjonen:

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

Nå kan vi påkalle metoden ved å konvertere String verdi til Operatør ved å bruke Operatør # valueOf () metode:

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

3.3. Kommandomønster

I forrige diskusjon har vi sett bruken av fabrikklasse for å returnere forekomsten av riktig forretningsobjekt for den gitte operatøren. Senere blir forretningsobjektet brukt til å utføre beregningen i Kalkulator.

Vi kan også designe en kalkulator # beregne metode for å godta en kommando som kan utføres på inngangene. Dette vil være en annen måte å erstatte nestet på hvis uttalelser.

Vi vil først definere vår Kommando grensesnitt:

offentlig grensesnitt Command {Integer execute (); }

La oss deretter implementere en Legg til 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; }}

Til slutt, la oss introdusere en ny metode i Kalkulator som godtar og utfører Kommando:

offentlig int beregne (Kommando kommando) {retur kommando. utføre (); }

Deretter kan vi påberope beregningen ved å starte en Legg til kommando og send den til Kalkulator # beregne metode:

@Test offentlig ugyldig 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 å skrive et stort antall nestede hvis uttalelser, viser hver av betingelsene en forretningsregel som må evalueres for at riktig logikk skal behandles. En regelmotor tar slik kompleksitet ut av hovedkoden. EN RuleEngine evaluerer Regler og returnerer resultatet basert på inngangen.

La oss gå gjennom et eksempel ved å designe et enkelt RuleEngine som behandler en Uttrykk gjennom et sett med Regler og returnerer resultatet fra det valgte Regel. Først definerer vi a Regel grensesnitt:

offentlig grensesnitt Regel {boolsk evaluering (uttrykk uttrykk); Resultat getResult (); }

For det andre, la oss implementere en RuleEngine:

public class RuleEngine {private static List rules = new ArrayList (); statisk {regler.add (ny AddRule ()); } offentlig resultatprosess (uttrykksuttrykk) {Rule rule = rules .stream () .filter (r -> r.evaluate (expression)) .findFirst () .orElseThrow (() -> new IllegalArgumentException ("Expression samsvarer ikke med noen Regel")); return rule.getResult (); }}

De RuleEngine godtar en Uttrykk innvender og returnerer Resultat. Nå, la oss designe Uttrykk klasse som en gruppe på to Heltall gjenstander med Operatør som vil bli brukt:

public class Expression {private Integer x; private Heltall y; privat operatør operatør; }

Og til slutt, la oss definere en skikk AddRule klasse som bare vurderer når ADD-operasjon er spesifisert:

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

Vi påkaller nå RuleEngine med en Uttrykk:

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

4. Konklusjon

I denne opplæringen utforsket vi en rekke forskjellige alternativer for å forenkle kompleks kode. Vi lærte også hvordan man kan erstatte nestede hvis uttalelser ved bruk av effektive designmønstre.

Som alltid kan vi finne den fullstendige kildekoden over GitHub-depotet.


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