Cara Mengganti Banyak jika Pernyataan di Jawa

1. Ikhtisar

Konstruksi keputusan adalah bagian penting dari bahasa pemrograman apa pun. Tapi kami mendarat di pengkodean sejumlah besar pernyataan jika bersarang yang membuat kode kami lebih kompleks dan sulit untuk dipelihara.

Dalam tutorial ini, kita akan membahas berbagai cara untuk mengganti pernyataan if bersarang .

Mari jelajahi berbagai opsi bagaimana kita dapat menyederhanakan kode.

2. Studi Kasus

Seringkali kita menjumpai logika bisnis yang melibatkan banyak kondisi, dan masing-masing membutuhkan pemrosesan yang berbeda. Demi demo, mari kita ambil contoh kelas Kalkulator . Kami akan memiliki metode yang mengambil dua angka dan operator sebagai input dan mengembalikan hasil berdasarkan operasi:

public int calculate(int a, int b, String operator) { 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; } return result; }

Kami juga dapat mengimplementasikan ini menggunakan pernyataan switch :

public int calculateUsingSwitch(int a, int b, String operator) { switch (operator) { case "add": result = a + b; break; // other cases } return result; }

Dalam perkembangan tipikal, pernyataan if mungkin tumbuh jauh lebih besar dan lebih kompleks di alam . Selain itu, pernyataan sakelar tidak cocok ketika ada kondisi yang kompleks .

Efek samping lain dari memiliki konstruksi keputusan bersarang adalah mereka menjadi tidak dapat dikelola. Misalnya, jika kita perlu menambahkan operator baru, kita harus menambahkan pernyataan if baru dan mengimplementasikan operasinya.

3. Refactoring

Mari jelajahi opsi alternatif untuk mengganti pernyataan if kompleks di atas menjadi kode yang lebih sederhana dan mudah dikelola.

3.1. Kelas Pabrik

Sering kali kami menemukan konstruksi keputusan yang akhirnya melakukan operasi serupa di setiap cabang. Ini memberikan kesempatan untuk mengekstrak metode pabrik yang mengembalikan objek dari tipe tertentu dan melakukan operasi berdasarkan perilaku objek konkret .

Sebagai contoh, mari kita definisikan antarmuka Operasi yang memiliki metode penerapan tunggal :

public interface Operation { int apply(int a, int b); }

Metode ini mengambil dua angka sebagai masukan dan mengembalikan hasilnya. Mari tentukan kelas untuk melakukan penambahan:

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

Kami sekarang akan mengimplementasikan kelas pabrik yang mengembalikan contoh Operasi berdasarkan operator yang diberikan:

public class OperatorFactory { static Map operationMap = new HashMap(); static { operationMap.put("add", new Addition()); operationMap.put("divide", new Division()); // more operators } public static Optional getOperation(String operator) { return Optional.ofNullable(operationMap.get(operator)); } }

Sekarang, di kelas Kalkulator , kita dapat meminta pabrik untuk mendapatkan operasi yang relevan dan menerapkan nomor sumber:

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

Dalam contoh ini, kita telah melihat bagaimana tanggung jawab didelegasikan ke objek yang digabungkan secara longgar yang dilayani oleh kelas pabrik. Tetapi mungkin ada kemungkinan di mana pernyataan bersarang jika hanya dialihkan ke kelas pabrik yang mengalahkan tujuan kita.

Alternatifnya, kita bisa memelihara repositori objek dalam Peta yang bisa ditanyakan untuk pencarian cepat . Seperti yang telah kita lihat OperatorFactory # operationMap melayani tujuan kita. Kita juga dapat menginisialisasi Map saat runtime dan mengkonfigurasinya untuk pencarian.

3.2. Penggunaan Enums

Selain penggunaan Map, kita juga dapat menggunakan Enum untuk memberi label pada logika bisnis tertentu . Setelah itu, kita dapat menggunakannya baik dalam bersarang jika pernyataan atau kasus beralih pernyataan . Alternatifnya, kami juga dapat menggunakannya sebagai pabrik objek dan menyusun strategi untuk melakukan logika bisnis terkait.

Itu akan mengurangi jumlah pernyataan if bersarang juga dan mendelegasikan tanggung jawab ke nilai Enum individu .

Mari kita lihat bagaimana kita bisa mencapainya. Pertama, kita perlu mendefinisikan Enum kita :

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

Seperti yang dapat kita amati, nilai adalah label dari berbagai operator yang akan digunakan lebih lanjut untuk penghitungan. Kami selalu memiliki opsi untuk menggunakan nilai sebagai kondisi berbeda dalam pernyataan if bersarang atau kasus sakelar, tetapi mari kita desain cara alternatif untuk mendelegasikan logika ke Enum itu sendiri.

Kami akan menentukan metode untuk setiap nilai Enum dan melakukan penghitungan. Misalnya:

ADD { @Override public int apply(int a, int b) { return a + b; } }, // other operators public abstract int apply(int a, int b);

Dan kemudian di kelas Kalkulator , kita dapat menentukan metode untuk melakukan operasi:

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

Sekarang, kita dapat memanggil metode dengan mengkonversi String nilai ke operator dengan menggunakan operator # valueOf () metode :

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

3.3. Pola Perintah

Dalam diskusi sebelumnya, kita telah melihat penggunaan kelas pabrik untuk mengembalikan instance objek bisnis yang benar untuk operator tertentu. Nantinya, objek bisnis digunakan untuk melakukan penghitungan di Kalkulator .

Kami juga dapat merancang metode Kalkulator # menghitung untuk menerima perintah yang dapat dieksekusi pada input . Ini akan menjadi cara lain untuk mengganti pernyataan if bersarang .

Kami pertama-tama akan menentukan antarmuka Perintah kami :

public interface Command { Integer execute(); }

Selanjutnya, mari kita terapkan AddCommand:

public class AddCommand implements Command { // Instance variables public AddCommand(int a, int b) { this.a = a; this.b = b; } @Override public Integer execute() { return a + b; } }

Terakhir, mari perkenalkan metode baru di Kalkulator yang menerima dan menjalankan Perintah :

public int calculate(Command command) { return command.execute(); }

Next, we can invoke the calculation by instantiating an AddCommand and send it to the Calculator#calculate method:

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

3.4. Rule Engine

When we end up writing a large number of nested if statements, each of the conditions depicts a business rule which has to be evaluated for the correct logic to be processed. A rule engine takes such complexity out of the main code. A RuleEngine evaluates the Rules and returns the result based on the input.

Let's walk through an example by designing a simple RuleEngine which processes an Expression through a set of Rules and returns the result from the selected Rule. First, we'll define a Rule interface:

public interface Rule { boolean evaluate(Expression expression); Result getResult(); }

Second, let's implement a RuleEngine:

public class RuleEngine { private static List rules = new ArrayList(); static { rules.add(new AddRule()); } public Result process(Expression expression) { Rule rule = rules .stream() .filter(r -> r.evaluate(expression)) .findFirst() .orElseThrow(() -> new IllegalArgumentException("Expression does not matches any Rule")); return rule.getResult(); } }

The RuleEngine accepts an Expression object and returns the Result. Now, let's design the Expression class as a group of two Integer objects with the Operator which will be applied:

public class Expression { private Integer x; private Integer y; private Operator operator; }

Dan terakhir, mari kita tentukan kelas AddRule khusus yang mengevaluasi hanya ketika Operasi ADD ditentukan:

public class AddRule implements Rule { @Override public boolean evaluate(Expression expression) { boolean evalResult = false; if (expression.getOperator() == Operator.ADD) { this.result = expression.getX() + expression.getY(); evalResult = true; } return evalResult; } }

Kami sekarang akan memanggil RuleEngine dengan Expression :

@Test public void whenNumbersGivenToRuleEngine_thenReturnCorrectResult() { Expression expression = new Expression(5, 5, Operator.ADD); RuleEngine engine = new RuleEngine(); Result result = engine.process(expression); assertNotNull(result); assertEquals(10, result.getValue()); }

4. Kesimpulan

Dalam tutorial ini, kami menjelajahi sejumlah opsi berbeda untuk menyederhanakan kode kompleks. Kami juga belajar bagaimana mengganti pernyataan bersarang if dengan menggunakan pola desain yang efektif.

Seperti biasa, kami dapat menemukan kode sumber lengkap melalui repositori GitHub.