State Design Pattern dengan Strategy Design Pattern sebenarnya agak-agak mirip. Tingkat kompleksitasnya juga rendah sama seperti Strategy Pattern sehingga cenderung lebih gampang dipahami, walaupun ga sepopuler Strategy Pattern.
State Design Pattern adalah Behavioral Design Pattern yang dapat mengubah behavior sebuah objek ketika internal state-nya berubah.
Design Pattern
Use Case
Misalkan kita ingin membuat sebuah aplikasi action/arcade gaming menggunakan console PlayStation, mirip dengan use case Strategy Pattern tapi dengan spesifikasi yang agak lain seperti berikut:
- Kita butuh object yang dapat mengimplementasi behavior Player berdasarkan tombol console yang digunakan;
- Kita dapat menentukan behavior algoritmanya berdasarkan character yang dipasang;
- Ketika memanggil method push triangle, maka player akan melakukan serangan dengan sebuah tinju (punch) sesuai character yang dipilih;
- Ketika memanggil method push cross, maka player akan melakukan serangan dengan sebuah tendangan (kick) sesuai character yang dipilih;
- Terdapat beberapa jenis character yang punya algoritma khas masing-masing untuk melakukan serangan tinju atau tendagan, jadi masing-masing karakter sudah punya algoritma tinju dan algoritma tendangannya masing-masing dan sudah sepaket;
- Behavior object menyesuaikan character yang dipasang;
Contoh code
Player Class
public class Player{
public void pushCross(String character){
if(character.equals("yoshimitsu")){
System.out.println("do flying kick to opponent");
}
if(character.equals("paul")){
System.out.println("do low kick to opponent's leg");
}
}
public void pushTriangle(String character){
if(character.equals("yoshimitsu")){
System.out.println("punch with sword");
}
if(character.equals("paul")){
System.out.println("do uppercut punch");
}
}
}
Contoh penggunaan
public static void main(String[] args){
Player player = new Player();
player.pushCross("paul");
player.pushTriangle("paul");
player.pushCross("yoshimitsu");
player.pushTriangle("yoshimitsu");
}
Code di atas sekilas ga beda jauh dengan code pada Strategy Pattern sebelumnya. Bedanya kali ini jurus tinju dan jurus tendangannya sudah sepaket sesuai masing-masing karakter, ga interchangable kayak use case Strategy Pattern.
Masalah
Secara umum masalahnya mirip-mirip dengan use case Strategy Pattern sebelumnya, seperti code yang akan sulit di-maintain ketika terjadi perubahan atau penambahan algoritma. Selain itu, setiap penambahan character, misalnya ingin menambahkan karakter Hwoarang dengan jurus algoritmanya Hwoarang, maka akan selalu terjadi perubahan pada semua method terkait, lebih painful lagi🤕.
Solusi
Sekarang mari kita refactor lagi kodenya😎.
Player Class
public class Player{
private PlayerCharacter character;
public void setCharacter(PlayerCharacter character){
this.character = character;
}
public void pushCross(){
character.kick();
}
public void pushTriangle(){
character.punch();
}
}
PlayerCharacter Interface
public interface PlayerCharacter{
void punch();
void kick();
}
Yoshimitsu Class
public class Yoshimitsu implements PlayerCharacter{
@Override
public void punch(){
System.out.println("punch with sword");
}
@Override
public void kick(){
System.out.println("do flying kick to opponent");
}
}
PaulPhoenix Class
public static class PaulPhoenix implements PlayerCharacter{
@Override
public void punch(){
System.out.println("do uppercut punch");
}
@Override
public void kick(){
System.out.println("do low kick to opponent's leg");
}
}
Contoh Penggunaan
public static void main(String[] args){
Player player = new Player();
player.setCharacter(new PaulPhoenix());
player.pushCross();
player.pushTriangle();
player.setCharacter(new Yoshimitsu());
player.pushCross();
player.pushTriangle();
}
Sekarang setiap mau ada penambahan karakter beserta algoritma jurusnya masing-masing tinggal bikin class baru dengan mengimplementasi PlayerCharacter interface. Ga perlu lagi mengubah code yang sudah berjalan, hanya seperlunya. Biaya maintenance jadi lebih ringan. Jika ingin mengubah behavior object player seperti Hwoarang, tinggal ganti state-nya menggunakan method setCharacter(new Hwoarang())
. Maka algoritma push triangle dan push cross akan mengikuti jurusnya Hwoarang.
Kenapa menggunakan State Design Pattern?
State Pattern digunakan jika kita ingin mengubah behavior sebuah objek berdasarkan implementasinya yang dipasang pada state objek tersebut. Jadi ketika state tersebut berubah dengan bentuk implementasi yang lain, algoritma objeknya juga ikut berubah. Ini cocok untuk permasalahan seperti di atas yang butuh perubahan behavior secara runtime yang algoritmanya sudah sepaket. Sejauh pengalaman gw, jarang banget gw menggunakan pendekatan ini, seringnya ketemu masalah yang bisa diselesaikan menggunakan Strategy Pattern. Selain itu, dengan menggunakan State Pattern artinya objek tersebut jadi mutable, sedangkan gw cukup menghindari pendekatan objek mutable kecuali emang itu satu-satunya solusi seperti yang pernah gw bahas sebelumnya.
Verdict
Bisa dibilang State Design Pattern ini adalah bentuk lain dari Strategy Design Pattern. State Pattern mengubah behaviornya ketika state pada objek tersebut diubah secara external. Sedangkan Strategy Pattern behaviornya berubah ketika menggunakan implementasi yang berbeda pada parameter.