Kami telah meninjau penggunaan objek tunggal, tetapi Anda mungkin belum menyadari bahwa strategi ini adalah pola desain, dan salah satu yang paling banyak digunakan pada saat itu.

Sebenarnya pola ini banyak sekali, dan bisa diklasifikasikan menurut tujuan khususnya.

Klasifikasi pola

Tipe pola Aplikasi
Penciptaan Jenis yang memecahkan masalah pembuatan objek
Struktural Pola yang memungkinkan kita membangun hierarki kelas yang benar dan dapat diperluas dalam arsitektur kita
Perilaku Kumpulan pola ini memfasilitasi interaksi yang aman dan nyaman antar objek dalam suatu program.

Biasanya, sebuah pola dicirikan oleh masalah yang dipecahkannya. Mari kita lihat beberapa pola yang paling sering kita jumpai saat bekerja dengan Java:

Pola Tujuan
lajang Kami sudah terbiasa dengan pola ini — kami menggunakannya untuk membuat dan mengakses kelas yang tidak boleh memiliki lebih dari satu instance.
Iterator Kami juga akrab dengan yang satu ini. Kita tahu bahwa pola ini memungkinkan kita mengulangi objek koleksi tanpa mengungkapkan representasi internalnya. Ini digunakan dengan koleksi.
Adaptor Pola ini menghubungkan objek yang tidak kompatibel sehingga dapat bekerja sama. Saya pikir nama pola adaptor membantu Anda membayangkan dengan tepat apa fungsinya. Berikut adalah contoh sederhana dari kehidupan nyata: adaptor USB untuk stopkontak.
Metode templat

Pola pemrograman perilaku yang memecahkan masalah integrasi dan memungkinkan Anda mengubah langkah algoritmik tanpa mengubah struktur algoritme.

Bayangkan kita memiliki algoritme perakitan mobil dalam bentuk urutan langkah perakitan:

Sasis -> Badan -> Mesin -> Interior Kabin

Jika kami memasang bingkai yang diperkuat, mesin yang lebih bertenaga, atau interior dengan pencahayaan tambahan, kami tidak perlu mengubah algoritme, dan urutan abstraknya tetap sama.

Penghias Pola ini membuat pembungkus untuk objek untuk memberikan fungsionalitas yang berguna. Kami akan mempertimbangkannya sebagai bagian dari artikel ini.

Di Java.io, kelas berikut mengimplementasikan pola:

Pola Di mana itu digunakan di java.io
Adaptor
Metode templat
Penghias

Pola dekorator

Bayangkan kita sedang mendeskripsikan model untuk desain rumah.

Secara umum, pendekatannya terlihat seperti ini:

Awalnya, kami memiliki pilihan beberapa tipe rumah. Konfigurasi minimum adalah satu lantai dengan atap. Kemudian kami menggunakan semua jenis dekorator untuk mengubah parameter tambahan, yang secara alami memengaruhi harga rumah.

Kami membuat kelas Rumah abstrak:


public abstract class House {
	String info;
 
	public String getInfo() {
    	return info;
	}
 
	public abstract int getPrice();
}
    

Di sini kami memiliki 2 metode:

  • getInfo() mengembalikan informasi tentang nama dan fitur rumah kami;
  • getPrice() mengembalikan harga konfigurasi rumah saat ini.

Kami juga memiliki implementasi Rumah standar — batu bata dan kayu:


public class BrickHouse extends House {
 
	public BrickHouse() {
    	info = "Brick House";
	}
 
	@Override
	public int getPrice() {
    	return 20_000;
	}
}
 
public class WoodenHouse extends House {
 
	public WoodenHouse() {
    	info = "Wooden House";
	}
 
	@Override
	public int getPrice() {
    	return 25_000;
	}
}
    

Kedua kelas mewarisi kelas Rumah dan mengganti metode harganya, menetapkan harga khusus untuk rumah standar. Kami menetapkan nama di konstruktor.

Selanjutnya, kita perlu menulis kelas dekorator. Kelas-kelas ini juga akan mewarisi kelas Rumah . Untuk melakukan ini, kami membuat kelas dekorator abstrak.

Di situlah kami akan menempatkan logika tambahan untuk mengubah objek. Awalnya, tidak akan ada logika tambahan dan kelas abstrak akan kosong.


abstract class HouseDecorator extends House {
}
    

Selanjutnya, kami membuat implementasi dekorator. Kami akan membuat beberapa kelas yang memungkinkan kami menambahkan fitur tambahan ke rumah:


public class SecondFloor extends HouseDecorator {
	House house;
 
	public SecondFloor(House house) {
    	this.house = house;
	}
 
	@Override
	public int getPrice() {
    	return house.getPrice() + 20_000;
	}
 
	@Override
	public String getInfo() {
    	return house.getInfo() + " + second floor";
	}
}
    
Seorang dekorator yang menambahkan lantai dua ke rumah kami

Konstruktor dekorator menerima rumah yang akan kita "hiasi", yaitu menambahkan modifikasi. Dan kami mengganti metode getPrice() dan getInfo() , mengembalikan informasi tentang rumah baru yang diperbarui berdasarkan yang lama.


public class Garage extends HouseDecorator {
 
	House house;
	public Garage(House house) {
    	this.house = house;
	}
 
	@Override
	public int getPrice() {
    	return house.getPrice() + 5_000;
	}
 
	@Override
	public String getInfo() {
    	return house.getInfo() + " + garage";
	}
}
    
Dekorator yang menambahkan garasi ke rumah kami

Sekarang kita bisa memperbarui rumah kita dengan dekorator. Untuk melakukan ini, kita perlu membuat rumah:


House brickHouse = new BrickHouse();
    

Selanjutnya, kita atur milik kitarumahvariabel sama dengan dekorator baru, melewati rumah kami:


brickHouse = new SecondFloor(brickHouse); 
    

KitarumahVariabel sekarang menjadi rumah dengan lantai dua.

Mari kita lihat kasus penggunaan yang melibatkan dekorator:

Kode contoh Keluaran

House brickHouse = new BrickHouse(); 

  System.out.println(brickHouse.getInfo());
  System.out.println(brickHouse.getPrice());
                    

Rumah Bata

20000


House brickHouse = new BrickHouse(); 

  brickHouse = new SecondFloor(brickHouse); 

  System.out.println(brickHouse.getInfo());
  System.out.println(brickHouse.getPrice());
                    

Rumah Bata + lantai dua

40000


House brickHouse = new BrickHouse();
 

  brickHouse = new SecondFloor(brickHouse);
  brickHouse = new Garage(brickHouse);

  System.out.println(brickHouse.getInfo());
  System.out.println(brickHouse.getPrice());
                    

Rumah Bata + lantai dua + garasi

45000


House woodenHouse = new SecondFloor(new Garage(new WoodenHouse())); 

  System.out.println(woodenHouse.getInfo());
  System.out.println(woodenHouse.getPrice());
                    

Rumah Kayu + garasi + lantai dua

50000


House woodenHouse = new WoodenHouse(); 

  House woodenHouseWithGarage = new Garage(woodenHouse);

  System.out.println(woodenHouse.getInfo());
  System.out.println(woodenHouse.getPrice());

  System.out.println(woodenHouseWithGarage.getInfo());
  System.out.println(woodenHouseWithGarage.getPrice());
                    

Rumah kayu

25000

Rumah Kayu + Garasi

30000

Contoh ini mengilustrasikan manfaat mengupgrade objek dengan dekorator. Jadi kami tidak mengubahrumah kayuobjek itu sendiri, melainkan membuat objek baru berdasarkan yang lama. Di sini kita dapat melihat bahwa keuntungan datang dengan kerugian: kita membuat objek baru di memori setiap kali, meningkatkan konsumsi memori.

Lihatlah diagram UML program kami ini:

Dekorator memiliki implementasi yang sangat sederhana dan secara dinamis mengubah objek, memutakhirkannya. Dekorator dapat dikenali oleh konstruktornya, yang menggunakan objek parameter dari tipe abstrak atau antarmuka yang sama dengan kelas saat ini. Di Java, pola ini banyak digunakan di kelas I/O.

Misalnya, seperti yang telah kita catat, semua subkelas java.io.InputStream , OutputStream , Reader dan Writer memiliki konstruktor yang menerima objek dari kelas yang sama.