Pendahuluan

Strategy Pattern merupakan salah satu Design pattern yang berguna untuk menyelesaikan masalah dengan kriteria sebagai berikut :

  • masalah yang membutuhkan keputusan di waktu runtime.
  • masalah yang alur prosesnya ditentukan tergantung dari inputan runtime oleh pengguna.
  • masalah yang mempunyai solusi yang bisa saling menggantikan di saat runtime..

Langsung contoh saja kali ya …

Misal :


- Aplikasi approval

Dimana ada misalnya 3 aksi approval, yaitu

  • Approve
  • Reject
  • Eskalasi Approval.

Tergantung dari aksi yang dilakukan, maka di sisi pemrosesan di backend, akan dilakukan alur/aksi yang berbeda untuk tiap pilihan aksi diatas.

Apakah bisa memakai pemrograman prosedural dengan kalang If…Then…Else ?

Tentu saja bisa, tetapi tidak/kurang elegan..

Bagaimana kalau ternyata ada tambahan flow lainnya, misalnya ditambahkan flow/aksi :

  • Return Back/Kembalikan (untuk kebutuhan mengembalikan approval ke requestor agar diperbaiki lagi).
  • Approve dengan catatan (misalnya dengan tambahan note dan email ke semua approver sebelumnya).
  • dll.

Sesuai dengan tujuan dibuatnya Design pattern yaitu agar solusi menjadi lebih elegan, maka menambahkan If…Then…Else dirasakan bukan cara yang elegan.

Dengan Strategy Pattern, maka akan lebih elegan.

Membuat sebuah interface yang sama untuk semua aksi diatas, kemudian mengimplementasikan tiap-tiap flow aksi approval diatas, dan memilih implementasi yang tepat/cocok di waktu aplikasi dijalankan sesuai dengan inputan pengguna.

Tentunya dengan menggunakan alur code yang sederhana dari sisi pengguna.

Itulah Strategy Pattern


Lalu apa hubungannya dengan Spring ?

Ok..ok..

Design pattern termasuk Strategy Pattern seperti diatas sudah jarang kita temui di aplikasi-aplikasi sekarang, karena biasanya sudah dibungkus dalam Framework, Library, dan tools yang ada.

Kita akan bersentuhan dengan Strategy Pattern ketika biasanya kita termasuk tim yang membuat core library untuk digunakan sebagai shared library oleh developer lain.

Atau bisa juga kita bersentuhan dengan Strategy Pattern ini ketika aplikasi kita masih aplikasi kecil, single fighter developer, atau kita berada di sebuah microservice yang spesifik.

Nah..hubugannya dengan Spring adalah…

Jeng..jeng..jeng…

Spring menyediakan fungsi untuk membantu kita dalam mengimplementasikan konsep Strategy Pattern ini.


Caranya ??

Ok, sekarang coba kita lihat bagaimana sebenarnya tahapan dalam implementasi Strategy Pattern secara umum :

  • Buat sebuah interface umum.
  • Buat beberapa class sebagai implementasi dari interface diatas, yang merepresentasikan alur / pilihan aksi.
  • Buat sebuah class Choicer atau StrategyManager, berguna untuk menentukan/memilih/me-list implementasi yang cocok/tepat berdasarkan inputan dari pengguna.
  • Selesai.

Nah di framework Spring, sudah dibantu di tahapan ke 3 diatas, yaitu pengganti class Choice atau Strategy Manager, yaitu dalam hal menentukan/memilih/m-elist implementasi yang cocok/tepat berdasarkan inputan dari pengguna.

Caranya seperti apa ?

  • Dengan kita mendeklarasikan List<InterfaceA> listA; , maka Spring otomatis akan memasukkan semua class yang implements InterfaceA ke dalam variable listA. Terserah nantinya kita akan melakukan iterasi terhadap List ini atau melakukan seleksi lagi terhadap listnya tersebut.

  • Dengan kita mendeklarasikan Map<String, InterfaceA> mapA; , maka Spring otomatis akan memasukkan semua class yang implements InterfaceA ke dalam variable mapA dengan key nya adalah String berupa nama bean nya. Nanti kita akan mudah untuk memilih atau mendapatkan class implementasi yang cocok berdasarkan pilihan kita.

Contoh codenya bagaimana ?

Misalnya :

Kita punya 3 pilihan approval :

  • Approve
  • Reject
  • Eskalasi Approval.

Kita buat sebuah interface untuk aksi yang terkait approval :

1public interface ApprovalAction {
2	 void action();
3}

Lalu kita buat 3 buah implementasi dari interface diatas :

1public class Approve implements ApprovalAction {
2  	void action() {
3      // do approve
4    }
5}
1public class Reject implements ApprovalAction {
2  	void action() {
3      // do reject
4    }
5}
1public class Eskalasi implements ApprovalAction {
2  	void action() {
3      // do eskalasi
4    }
5}

Lalu kita bisa buat class wrapper untuk mendapatkan class yang sesuai

 1@Component
 2public class ApprovalStrategy {
 3
 4   @Autowired
 5   Map<String, ApprovalAction> approvalActionMap;
 6
 7   public void doApproval(String approvalType) {
 8      approvalActionMap.get(approvalType).action();
 9   }
10}

Baris ke - 5 , merupakan fasilitas dari Spring, yang otomatis akan meload class berikut ke dalam sebuah map :

  • class Approve
  • class Reject
  • class Eskalasi

Ketiga class tersebut mengimplementasikan interface ApprovalAction.

key dari map tersebut bertipe String dan merupakan nama bean dari class-class yang mengimplementasikan interface ApprovalAction tersebut.

Sehingga map diatas akan berisi data map sbb :

  • key:approve , value: object Approve
  • key:reject , value: object Reject
  • key:eskalasi , value: object Eskalasi

Kemudian kita bisa buat class controller untuk mendapatkan nilai inputan approvalType dari masukan pengguna.

 1@RestController
 2public class OrderController {
 3
 4  @Autowired
 5  private ApprovalStrategy approvalStrategy;
 6
 7  @PostMapping("/approve")
 8  public void approval(@RequestParam String approvalType) {
 9     approvalStrategy.doApproval(approvalType);
10  }
11}

Dari controller diatas, kita bisa mengetes melalui url :

  • http://localhost/approve?approvalType=approve
  • http://localhost/approve?approvalType=reject
  • http://localhost/approve?approvalType=eskalasi

Di class controller diatas, kita tidak perlu menambahkan code If…Then…Else untuk memilih class yang cocok tergantung dari jenis approvalnya.

Dengan memakai bantuan Spring Strategy Pattern diatas, maka otomatis kita bisa mendapatkan mapping yang mudah untuk class-class implementasi dari Strategy Pattern tersebut.