Ako nahradiť veľa príkazov if v jazyku Java

1. Prehľad

Konštrukty rozhodovania sú dôležitou súčasťou každého programovacieho jazyka. Ale skončili sme v kódovaní obrovského počtu vnorených príkazov if, ktoré robia náš kód zložitejším a náročnejším na údržbu.

V tomto výučbe sa pozrieme na rôzne spôsoby nahradenia vnorených príkazov if.

Poďme preskúmať rôzne možnosti, ako môžeme zjednodušiť kód.

2. Prípadová štúdia

Často sa stretávame s obchodnou logikou, ktorá vyžaduje veľa podmienok a každá z nich vyžaduje iné spracovanie. Z dôvodu ukážky si vezmime príklad a Kalkulačka trieda. Budeme mať metódu, ktorá vezme dve čísla a operátor ako vstup a vráti výsledok na základe operácie:

public int vypočítať (int a, int b, operátor reťazca) {int result = Integer.MIN_VALUE; if ("add" .equals (operator)) {result = a + b; } else if ("multiply" .equals (operator)) {result = a * b; } else if ("divide" .equals (operator)) {result = a / b; } else if ("subtract" .equals (operator)) {result = a - b; } vrátiť výsledok; }

Môžeme to implementovať aj pomocou prepínač Vyhlásenia:

public int countUsingSwitch (int a, int b, operátor reťazca) {switch (operátor) {case "add": result = a + b; prestávka; // ďalšie prípady} vrátiť výsledok; }

V typickom vývoji výroky if môžu mať oveľa väčší a zložitejší charakter. Tiež prepínacie tvrdenia sa nehodia dobre, ak sú zložité podmienky.

Ďalším vedľajším účinkom vnorených rozhodovacích konštrukcií je, že sa stávajú nezvládnuteľnými. Napríklad, ak potrebujeme pridať nového operátora, musíme pridať nový príkaz if a implementovať operáciu.

3. Refaktoring

Poďme preskúmať alternatívne možnosti na nahradenie komplexných príkazov if do oveľa jednoduchšieho a spravovateľného kódu.

3.1. Trieda továrne

Mnohokrát sa stretneme s rozhodovacími konštruktmi, ktoré nakoniec urobia podobnú operáciu v každej vetve. Toto poskytuje príležitosť extrahujte továrenskú metódu, ktorá vráti objekt daného typu a vykoná operáciu na základe správania konkrétneho objektu.

Pre náš príklad definujme Prevádzka rozhranie, ktoré má jeden uplatniť metóda:

verejné rozhranie Prevádzka {int apply (int a, int b); }

Metóda berie ako vstup dve čísla a vráti výsledok. Definujme triedu na vykonávanie doplnkov:

verejná trieda Dodatok implementuje operáciu {@Override public int apply (int a, int b) {return a + b; }}

Teraz implementujeme továrenskú triedu, ktorá vracia inštancie Prevádzka na základe daného operátora:

verejná trieda OperatorFactory {statická mapa operationMap = nový HashMap (); static {operationMap.put ("add", new Addition ()); operationMap.put ("divide", new Division ()); // viac operátorov} public static Voliteľné getOperation (operátor reťazca) {return Optional.ofNullable (operationMap.get (operator)); }}

Teraz, v Kalkulačka triedy, môžeme dopytovať továreň, aby sme získali príslušnú operáciu a použili na zdrojové čísla:

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

V tomto príklade sme videli, ako je zodpovednosť delegovaná na voľne spojené objekty obsluhované továrenskou triedou. Mohli by však existovať šance, že výkazy vnorené, ak sa jednoducho presunú do továrenskej triedy, ktorá porušuje náš účel.

Prípadne môžeme udržiavať úložisko objektov v a Mapa na ktoré by bolo možné vyhľadať. Ako sme videli OperatorFactory # operationMap slúži nášmu účelu. Môžeme tiež inicializovať Mapa za behu a nakonfigurujte ich na vyhľadávanie.

3.2. Používanie Enums

Okrem použitia Mapa, môžeme tiež použiť Enum označiť konkrétnu obchodnú logiku. Potom ich môžeme použiť buď vo vnorených ak vyhlásenia alebo spínacia skrinkaVyhlásenia. Prípadne ich môžeme tiež použiť ako továreň na objekty a strategizovať ich tak, aby vykonávali súvisiacu obchodnú logiku.

To by tiež znížilo počet vnorených príkazov if a zodpovednosť by sa delegovala na jednotlivca Enum hodnoty.

Pozrime sa, ako to môžeme dosiahnuť. Spočiatku si musíme definovať svoje Enum:

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

Ako vidíme, hodnoty sú štítkami rôznych operátorov, ktoré sa budú ďalej používať na výpočet. Vždy máme možnosť použiť hodnoty ako rôzne podmienky vo vnorených príkazoch if alebo switch cases, navrhnime však alternatívny spôsob delegovania logiky na Enum sám.

Definujeme metódy pre každú z nich Enum hodnoty a urobte výpočet. Napríklad:

PRIDAŤ {@Override public int apply (int a, int b) {return a + b; }}, // ostatní operátori public abstract int apply (int a, int b);

A potom v Kalkulačka triedy môžeme definovať spôsob vykonania operácie:

public int count (int a, int b, Operator operator) {return operator.apply (a, b); }

Teraz môžeme metódu vyvolať pomocou prevádzanie String hodnota do Prevádzkovateľ pomocou Operátor # valueOf () metóda:

@Test public void whenCalculateUsingEnumOperator_thenReturnCorrectResult () {Calculator calculator = new Calculator (); int výsledok = calculator.calculate (3, 4, Operator.valueOf ("ADD")); assertEquals (7, výsledok); }

3.3. Veliteľský vzor

V predchádzajúcej diskusii sme videli použitie triedy factory na vrátenie inštancie správneho obchodného objektu pre daného operátora. Neskôr sa obchodný objekt použije na vykonanie výpočtu v Kalkulačka.

Môžeme aj navrhnúť kalkulačka # vypočítať metóda na prijatie príkazu, ktorý sa dá vykonať na vstupoch. Toto bude ďalší spôsob výmeny vnorených ak vyhlásenia.

Najskôr si zadefinujeme naše Velenie rozhranie:

verejné rozhranie Príkaz {Celé číslo spustiť (); }

Ďalej implementujeme AddCommand:

verejná trieda AddCommand implementuje príkaz {// Premenné inštancie public AddCommand (int a, int b) {this.a = a; this.b = b; } @Override public Integer execute () {return a + b; }}

Na záver si predstavíme novú metódu v Kalkulačka ktorá prijíma a vykonáva Velenie:

public int count (príkazový príkaz) {návrat command.execute (); }

Ďalej môžeme výpočet vyvolať pomocou inštancie AddCommand a pošlite ho do Kalkulačka # vypočítať metóda:

@Test public void whenCalculateUsingCommand_thenReturnCorrectResult () {Calculator calculator = new Calculator (); int výsledok = calculator.calculate (nový AddCommand (3, 7)); assertEquals (10, výsledok); }

3.4. Pravidlový motor

Keď skončíme s písaním veľkého počtu vnorených príkazov if, každá z podmienok zobrazuje obchodné pravidlo, ktoré je potrebné vyhodnotiť, aby sa mohla spracovať správna logika. Pravidlo engine odstraňuje takú zložitosť z hlavného kódu. A RuleEngine hodnotí Pravidlá a vráti výsledok na základe vstupu.

Poďme si prejsť príkladom navrhnutím jednoduchého RuleEngine ktorý spracováva an Vyjadrenie prostredníctvom súboru Pravidlá a vráti výsledok z vybratého Pravidlo. Najskôr definujeme a Pravidlo rozhranie:

verejné rozhranie Rule {boolean vyhodnotiť (výrazový výraz); Výsledok getResult (); }

Po druhé, poďme implementovať a RuleEngine:

verejná trieda RuleEngine {súkromné ​​statické pravidlá zoznamu = nový ArrayList (); static {rules.add (nové AddRule ()); } public Result process (Expression expression) {Rule rule = rules .stream () .filter (r -> r.evaluate (expression)) .findFirst () .orElseThrow (() -> new IllegalArgumentException ("Výraz sa nezhoduje so žiadnym Pravidlo ")); vrátiť pravidlo.getResult (); }}

The RuleEngine prijíma Vyjadrenie objekt a vráti Výsledok. Teraz, poďme navrhnúť Vyjadrenie triedy ako skupina dvoch Celé číslo predmety s Prevádzkovateľ ktoré sa použijú:

public class Expression {private Integer x; súkromné ​​celé číslo y; súkromný operátor; }

A nakoniec definujme zvyk AddRule trieda, ktorá hodnotí iba vtedy, keď PRIDAŤ operáciu je zadané:

verejná trieda AddRule implementuje pravidlo {@Override verejné boolean vyhodnotenie (výrazový výraz) {boolean evalResult = false; if (expression.getOperator () == Operator.ADD) {this.result = expression.getX () + expression.getY (); evalResult = true; } návrat evalResult; }}

Teraz vyvoláme RuleEngine s Vyjadrenie:

@Test public void whenNumbersGivenToRuleEngine_thenReturnCorrectResult () {Expression expression = new Expression (5, 5, Operator.ADD); Motor RuleEngine = nový RuleEngine (); Výsledok výsledok = engine.process (výraz); assertNotNull (výsledok); assertEquals (10, result.getValue ()); }

4. Záver

V tomto tutoriáli sme preskúmali množstvo rôznych možností na zjednodušenie zložitého kódu. Tiež sme sa naučili, ako nahradiť vnorené vyhlásenia if pomocou efektívnych návrhových vzorov.

Ako vždy môžeme nájsť kompletný zdrojový kód cez úložisko GitHub.


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