Selama beberapa bulan terakhir, saya tersandung beberapa kali selama teknik / pola berikut. Namun, sepertinya saya tidak dapat menemukan nama tertentu, saya juga tidak 100% yakin tentang semua kelebihan dan kekurangannya.
Polanya berbunyi sebagai berikut:
Dalam antarmuka Java, seperangkat metode umum didefinisikan seperti biasa. Namun, menggunakan kelas dalam, instance default bocor melalui antarmuka.
public interface Vehicle {
public void accelerate();
public void decelerate();
public static class Default {
public static Vehicle getInstance() {
return new Car(); // or use Spring to retrieve an instance
}
}
}
Bagi saya, tampaknya keuntungan terbesar terletak pada kenyataan bahwa seorang pengembang hanya perlu tahu tentang antarmuka dan bukan implementasinya, misalnya jika dia ingin segera membuat contoh.
Vehicle someVehicle = Vehicle.Default.getInstance();
someVehicle.accelerate();
Selain itu, saya telah melihat teknik ini digunakan bersama-sama dengan Spring untuk secara dinamis memberikan contoh tergantung pada konfigurasi. Dalam hal ini, sepertinya ini juga dapat membantu dengan modularisasi.
Namun demikian, saya tidak dapat menghilangkan perasaan bahwa ini adalah penyalahgunaan antarmuka karena menggabungkan antarmuka dengan salah satu implementasinya. (Prinsip inversi ketergantungan dll.) Adakah yang bisa menjelaskan kepada saya bagaimana teknik ini disebut, serta kelebihan & kekurangannya?
Memperbarui:
Setelah beberapa waktu untuk dipertimbangkan, saya memeriksa kembali dan memperhatikan bahwa versi pola singleton berikut ini digunakan jauh lebih sering. Dalam versi ini, instance statis publik diekspos melalui antarmuka yang diinisialisasi hanya sekali (karena bidangnya final). Selain itu, instance hampir selalu diambil menggunakan Spring atau pabrik generik yang memisahkan antarmuka dari implementasi.
public interface Vehicle {
public void accelerate();
public void decelerate();
public static class Default {
public static final Vehicle INSTANCE = getInstance();
private static Vehicle getInstance() {
return new Car(); // or use Spring/factory here
}
}
}
// Which allows to retrieve a singleton instance using...
Vehicle someVehicle = Vehicle.Default.INSTANCE;
Singkatnya: tampaknya ini adalah pola pabrik tunggal / custom, yang pada dasarnya memungkinkan untuk mengekspos instance atau singleton melalui antarmuka-nya. Sehubungan dengan kerugian, beberapa telah disebutkan dalam jawaban & komentar di bawah ini. Sejauh ini, keuntungan tampaknya terletak pada kenyamanannya.
sumber
Vehicle.Default
harus dipindahkan ke namespace paket sebagai kelas pabrik, misVehicleFactory
.Vehicle.Default.getInstance() != Vehicle.Default.getInstance()
Jawaban:
Default.getInstance
adalah IMHO hanya bentuk yang sangat spesifik dari metode pabrik , dicampur dengan konvensi penamaan yang diambil dari pola tunggal (tetapi tanpa implementasi yang terakhir). Dalam bentuk saat ini, ini merupakan pelanggaran terhadap " prinsip tanggung jawab tunggal ", karena antarmuka (yang sudah melayani tujuan mendeklarasikan API kelas) mengambil tanggung jawab tambahan untuk menyediakan contoh default, yang akan jauh lebih baik ditempatkan di tempat terpisah.VehicleFactory
kelas.Masalah utama yang disebabkan oleh konstruk ini adalah bahwa ia menginduksi ketergantungan siklik antara
Vehicle
danCar
. Misalnya, dalam formulir saat ini tidak akan mungkin untuk ditempatkanVehicle
di satu perpustakaan, danCar
di yang lain. Menggunakan kelas pabrik yang terpisah dan menempatkanDefault.getInstance
metode di sana akan menyelesaikan masalah itu. Mungkin juga merupakan ide yang baik untuk memberikan nama yang berbeda pada metode itu, untuk mencegah kebingungan terkait dengan lajang. Jadi hasilnya bisa sepertiVehicleFactory.createDefaultInstance()
sumber
VehicleFactory
lebih konvensional daripada konstruk bersarangVehicle.Default
, terutama dengan metode "getInstance" yang menyesatkan. Meskipun mungkin untuk menghindari ketergantungan siklik dengan menggunakan Spring, saya pribadi lebih suka varian pertama hanya karena akal sehat. Dan, tetap saja memberi Anda pilihan untuk memindahkan pabrik ke komponen yang berbeda, mengubah implementasi setelahnya untuk bekerja tanpa Spring dll.autodrive()
metode. Mobil Anda yang sangat generik kemudian harus berubah untuk menerapkan metode itu, misalnya dengan melempar NotImplementedException, tetapi itu tidak memberi alasan tambahan untuk berubah pada Kendaraan.Ini terlihat seperti pola Objek Null bagi saya.
Tetapi itu sangat tergantung pada bagaimana
Car
kelas diimplementasikan. Jika diimplementasikan dengan cara "netral", maka itu jelas merupakan Objek Null. Itu berarti, jika Anda dapat menghapus semua pemeriksaan nol pada antarmuka dan membuat instance kelas ini alih-alih setiap kemunculannyanull
, maka kode masih harus bekerja dengan benar.Juga jika ini adalah pola ini, maka tidak ada masalah untuk membuat kopling ketat antara antarmuka itu sendiri dan implementasi objek nol. Karena objek nol bisa ada di mana-mana di mana antarmuka kata digunakan
sumber