Contoh Bridge Design Pattern
Sun. Aug 29th, 2021 05:40 PM3 mins read
Contoh Bridge Design Pattern
Source: flickr@Theo Crazzolara - Tower Bridge London

Bridge Design Pattern termasuk salah satu design pattern yang agak kompleks dibanding design pattern yang lain. Penggunaan design pattern ini juga tidak terlalu populer. Design pattern ini biasanya digunakan untuk memisahkan hierarki sebuah class menjadi lebih independen sehingga pengimplementasiannya bisa lebih spesifik dan fleksibel.

Bridge Design Pattern adalah Structural Design Pattern yang memisahkan sebuah class yang lebih besar atau saling berkaitan menjadi beberapa hierarki yang berbeda sehingga masing-masing class bisa dikembangkan secara independen satu sama lain.

Design Pattern

Use Case

Kita akan membuat aplikasi yang ingin menampilkan komposisi mie.

  • Dibutuhkan beberapa jenis mie seperti mie goreng dan mie rebus;
  • Masing-masing mie tersebut memiliki topping seperti telur dan bakso yang interchangeable;

Contoh Code

Noodle Interface

public interface Noodle{
	void printNoodles();
}

BoildeNoodle Abstract Class

public abstract class BoiledNoodle implements Noodle{
	@Override
	public void printNoodles(){
		System.out.println(getDescription());
	}

	protected String getDescription(){
		return "This is the delicious Boiled Noodle";
	}
}

BoiledNoodleWithEgg Class

public class BoiledNoodleWithEgg extends BoiledNoodle{
	@Override
	public void printNoodles(){
		System.out.println(getDescription() + " with sunny side up");
	}
}

BoiledNoodleWithMeatBall Class

public class BoiledNoodleWithMeatball extends BoiledNoodle{
	@Override
	public void printNoodles(){
		System.out.println(getDescription() + " with meatball");
	}
}

FriedNoodle Abstract Class

public abstract class FriedNoodle implements Noodle{
	@Override
	public void printNoodles(){
		System.out.println(getDescription());
	}

	protected String getDescription(){
		return "Fried Noodle is the best noodle";
	}
}

FriedNoodleWithEgg Class

public class FriedNoodleWithEgg extends FriedNoodle{
	@Override
	public void printNoodles(){
		System.out.println(getDescription() + " with sunny side up");
	}
}

FriedNoodleWithMeatBall Class

public class FriedNoodleWithMeatball extends FriedNoodle{
	@Override
	public void printNoodles(){
		System.out.println(getDescription() + " with meatball");
	}
}

Contoh Penggunaan

public static void main(String[] args){
	Noodle boiledNoodleWithEgg = new BoiledNoodleWithEgg();
	boiledNoodleWithEgg.printNoodles();
	System.out.println();
	Noodle friedNoodleWithEgg = new FriedNoodleWithEgg();
	friedNoodleWithEgg.printNoodles();
	System.out.println();
	Noodle boiledNoodleWithMeatBall = new BoiledNoodleWithMeatball();
	boiledNoodleWithMeatBall.printNoodles();
}

Kita coba menggunakan pendekatan seperti Template Method Design Pattern seperti sebelumnya. Kita menggunakan inheritance untuk membuat hierarki dari Noodle hingga Noodle beserta tipe dan toppingnya masing-masing.

Masalah

Dari pertama liat mungkin udah pada tau masalahnya😅. Benar, code di atas cukup kompleks. Menggunakan inheritance untuk menggunakan kembali sebuah code memang bad practice. Hierarki class di atas susah untuk dikembangkan ketika terjadi perubahan. Misalnya ada penambahan tipe mie seperti mie tumis, atau penambahan jenis topping seperti keju, maka makin kompleks lagi nanti hierarkinya. Kita jadi bakal bikin pasangan-pasangan class tersebut setiap perubahan. Jadi Template Method Design Pattern bukan solusi untuk kasus yang satu ini.

Solusi

Sekarang mari liat Bridge Design Pattern😎.

Noodle Interface

public interface Noodle{
	void printNoodles();
}

Topping Interface

public interface Topping{
	String getName();
}

BoiledNoodle Class

public class BoiledNoodle implements Noodle{
	private final Topping topping;

	public BoiledNoodle(Topping topping){
		this.topping = topping;
	}

	@Override
	public void printNoodles(){
		System.out.println("This is the delicious Boiled Noodle with " + topping.getName());
	}
}

FriedNoodle Class

public class FriedNoodle implements Noodle{
	private final Topping topping;

	public FriedNoodle(Topping topping){
		this.topping = topping;
	}

	@Override
	public void printNoodles(){
		System.out.println("Fried Noodle is the best noodle with " + topping.getName());
	}
}

EggTopping Class

public class EggTopping implements Topping{
	@Override
	public String getName(){
		return "sunny side up";
	}
}

MeatBallTopping Class

public class MeatBallTopping implements Topping{
	@Override
	public String getName(){
		return "Malang Meatball";
	}
}

Contoh Penggunaan

public static void main(String[] args){
	Noodle boiledNoodleWithEgg = new BoiledNoodle(new EggTopping());
	boiledNoodleWithEgg.printNoodles();
	System.out.println();
	Noodle boiledNoodleWithMeatBall = new BoiledNoodle(new MeatBallTopping());
	boiledNoodleWithMeatBall.printNoodles();
	System.out.println();
	Noodle friedNoodleWithEgg = new FriedNoodle(new EggTopping());
	friedNoodleWithEgg.printNoodles();
}

Nah, sekarang antara mie dan topping kita pisah hierarkinya. Kita menghubungkan antara mie dan topping lewat composition, bukan inheritance lagi. Dengan begitu lebih interchangeable ketika dipasang-pasangkan. Selanjutnya setiap penambahan tipe mie atau topping tinggal implementasi class baru secara independen. User nantinya yang menentukan tipe mie dan topping apa yang diinginkan ketika melakukan pembuatan instance object.

Kenapa menggunakan Bridge Design Pattern

Dengan Bridge Design Pattern, kita memecah monolitik class menjadi beberapa varian. Kita bisa mengimplementasi Bridge Design Pattern ketika beberapa dimensi class diidentifikasi cukup complex seperti permasalah di atas. Dengan Bridge Design Pattern, user bisa menentukan implementasi yang diinginkan saat runtime dengan melakukan dependency injection. Tapi, penggunaan dengan objek yang memiliki kohesi yang cukup tinggi juga bisa mengakibatkan code menjadi kompleks. Misalnya selain topping, kita juga ingin menambahkan merk mie, rasa mie, dan sebagainya, sehingga dependency-nya juga bisa menjadi lebih besar lagi.

Verdict

Intinya dengan Bridge Design Pattern kita bisa memecah sebuah class yang besar dengan hierarki yang nantinya cukup kompleks menjadi beberapa varian kecil yang interchangeable sehingga perubahannya dilakukan secara independen. Code kita jadi mengimplementasi Open/Closed Principle. Gw sendiri pernah melakukan pendekatan ini ketika melakukan refactor legacy code yang menggunakan inheritance untuk menggunakan kembali beberapa behavior. Tentu saja itu cukup menyulitkan mocking object ketika membuat unit testing. Dengan Bridge dan Adapater Design Pattern gw bisa menghubungkan legacy class dan mengkonversinya menjadi objek baru secara composition sehingga lebih mudah dikembangkan.

© 2024 · Ferry Suhandri