Kali ini, seperti janji di akhir postingan Strategy Pattern Bagian 2, kita akan mengintegrasikan duck behaviors ke dalam kelas Duck. Kuncinya, Duck sekarang akan mendelegasikan flying dan quacking behaviors, dan bukan mendefinisikan flying dan quacking method di class Duck atau subclasses-nya.
Bagaimana caranya?
Ok, kita akan melihat dulu kelas Duck yang telah dimodifikasi. Kelasnya akan seperti ini.

Kenapa kelas Duck menjadi seperti itu, ini langkah-langkahnya.
Pertama, kita menambahkan dua instance variables ke dalam kelas Duck. Sebut saja flyBehavior dan quackBehavior. Dua instance variables ini dideklarasikan dengan bertipe interface dan bukan bertipe implementasi konkrit. Tiap objek Duck akan men-set variables ini secara polimorfis dengan reference dari behavior type tertentu yang diinginkan saat runtime, misalnya FlyWith Wings, Quack, dsb.
Kita juga menghapus method fly() dan quack() dari kelas Duck serta subclasses-nya karena kita telah memindahkan behavior ini ke kelas-kelas FlyBehavior dan QuackBehavior.
fly() dan quack() pada kelas Duck diganti dengan dua method yang mirip yang dinamakan dengan performFly() dan performQuack(). Cara kerja dari kedua method ini akan kita lihat sebentar lagi.
Kedua, kita implementasikan performQuack():
public class Duck {
QuackBehavior quackBehavior;
// kode lainnya
public void performQuack() {
quackBehavior.quack();
}
}
Masing-masing Duck mempunyai reference ke sesuatu yang mengimplementasikan interface QuackBehavior.
Untuk melakukan quack, sebuah objek Duck tinggal mengijinkan objek yang di-reference oleh quackBehavior untuk ber-quack. Jadi, pada kode ini kita tidak peduli objek macam apa ini, yang kita pedulikan yaitu objek ini tahu bagaimana untuk ber-quack().
Ketiga, kita men-set instance variables flyBehavior dan quackBehavior. Tapi bagaimana caranya? Ok, sekarang kita lihat kelas MallardDuck:
public class MallardDuck extends Duck {
public MallardDuck() {
quackBehavior = new Quack();
flyBehavior = new FlyWithWings();
}
public void display() {
System.out.println("Saya adalah Mallard duck");
}
}
Seekor MallardDuck menggunakan kelas Quack untuk menangani suara kwek-nya. Ketika performQuack dipanggil, tanggung-jawab untuk ber-kwek didelegasikan kepada objek Quack. Kemudian kita dapat suara kwek-kwek-kwek. Untuk flyBehavior-nya, MallardDuck menggunakan FlyWithWings.
Kenapa bisa seperti ini? Ketika MallardDuck di-instance-kan, constructor-nya meng-inisialisasi instance variable quackBehavior dengan instance baru yang bertipe Quack() (kelas yang merupakan implementasi konkrit dari QuackBehavior). Begitu juga dengan flying behavior. Constructor dari MallardDuck meng-inisialisasi instance variable flyBehavior dengan instance dari FlyWithWings yang merupakan kelas implementasi konkrit dari FlyBehavior.
CODING TIME!
Setelah kita berkata-kata panjang lebar, saatnya untuk sedikit melakukan coding dan compile untuk mengetes solusi di atas.
Pertama, kita tuliskan kode kelas Duck (Duck.java) dan kelas MallardDuck (MallardDuck.java).
public abstract class Duck {
FlyBehavior flyBehavior;
QuackBehavior quackBehavior;
public Duck() {
}
public abstract void display();
public void performFly() {
flyBehavior.fly(); // mendelegasikan ke behavior class
}
public void performQuack() {
quackBehavior.quack(); // mendelegasikan ke behavior class
}
public void swim() {
System.out.println("Saya Berenang....!");
}
}
public class MallardDuck extends Duck {
public MallardDuck() {
quackBehavior = new Quack();
flyBehavior = new FlyWithWings();
}
public void display() {
System.out.println("Saya adalah Mallard duck");
}
}
Kemudian kita compile.
Selanjutnya, kita tuliskan kode interface FlyBehavior (FlyBehavior.java) dan dua kelas implementasi behavior FlyWithWings (FlyWithWings.java) dan FlyNoWay (FlyNoWay.java).
public interface FlyBehavior {
public void fly(); // method fly perlu di-override oleh
// class yang mengimplementasikan
// interface ini
}
public class FlyWithWings implements FlyBehavior {
public void fly() {
System.out.println("Saya terbang....!");
}
}
public class FlyNoWay implements FlyBehavior {
public void fly() {
System.out.println("Saya tidak dapat terbang
");
}
}
Kemudian kita compile.
Selanjutnya, giliran interface QuackBehavior (QuackBehavior.java) dan tiga kelas implementasinya yaitu Quack.java, MuteQuack.java, dan Squeak.java.
public class Quack implements QuackBehavior {
public void quack() {
System.out.println("Quack.....");
}
}
public class Squeak implements QuackBehavior {
public void quack() {
System.out.println("Squeak....");
}
}
public class MuteQuack implements QuackBehavior {
public void quack() {
System.out.println("<< Tidak bersuara >>");
}
}
Kemudian kita compile juga.
Kelas-kelas kita sudah dituliskan. Sekarang saatnya mengetes kelas-kelas tersebut dengan membuat kelas tester. Jadi tester yang digunakan adalah kelas seperti ini (MiniDuckSimulator.java).
public class MiniDuckSimulator {
public static void main(String[] args) {
Duck mallard = new MallardDuck();
mallard.performQuack();
mallard.performFly();
}
}
Kita compile, dijalankan dan outputnya adalah…….

Yep, sesuai dengan yang kita harapkan.
Ok, ini bukanlah akhir cerita. Kita belum menyinggung apanya yang dinamakan Strategy Pattern. Oleh karena itu kita perlu wrap-up cerita panjang ini dan itu akan dilakukan di postingan selanjutnya di Strategy Pattern Bagian 4. Don’t miss it….











