Apakah praktik yang aman untuk menggunakan metode default sebagai sifat versi pria yang buruk di Java 8?
Beberapa orang mengklaim mungkin membuat panda sedih jika Anda menggunakannya hanya untuk kepentingan saja, karena itu keren, tapi itu bukan niat saya. Juga sering diingatkan bahwa metode default diperkenalkan untuk mendukung evolusi API dan kompatibilitas mundur, yang memang benar, tetapi ini tidak membuatnya salah atau dipelintir untuk menggunakannya sebagai ciri-ciri itu sendiri.
Saya memiliki kasus penggunaan praktis berikut ini :
public interface Loggable {
default Logger logger() {
return LoggerFactory.getLogger(this.getClass());
}
}
Atau mungkin, tentukan PeriodTrait
:
public interface PeriodeTrait {
Date getStartDate();
Date getEndDate();
default isValid(Date atDate) {
...
}
}
Memang, komposisi dapat digunakan (atau bahkan kelas pembantu) tetapi tampaknya lebih bertele-tele dan berantakan dan tidak memungkinkan untuk mendapatkan keuntungan dari polimorfisme.
Jadi, apakah boleh / aman menggunakan metode default sebagai ciri dasar , atau haruskah saya khawatir tentang efek samping yang tidak terduga?
Beberapa pertanyaan tentang SO terkait dengan ciri-ciri Java vs Scala; bukan itu intinya di sini. Saya tidak hanya meminta pendapat saja. Sebaliknya, saya mencari jawaban yang berwibawa atau setidaknya wawasan lapangan: jika Anda telah menggunakan metode default sebagai ciri-ciri pada proyek perusahaan Anda, apakah itu berubah menjadi bom waktu?
sumber
Jawaban:
Jawaban singkatnya adalah: aman jika Anda menggunakannya dengan aman :)
Jawaban yang tajam: beri tahu saya apa yang Anda maksud dengan sifat, dan mungkin saya akan memberikan jawaban yang lebih baik :)
Secara serius, istilah "sifat" tidak didefinisikan dengan baik. Banyak pengembang Java yang paling akrab dengan ciri-ciri seperti yang diungkapkan dalam Scala, tetapi Scala jauh dari bahasa pertama yang memiliki ciri-ciri, baik dalam nama atau efeknya.
Misalnya, di Scala, sifat bersifat stateful (dapat memiliki
var
variabel); di Fortress mereka adalah perilaku murni. Antarmuka Java dengan metode default tidak memiliki kewarganegaraan; apakah ini berarti mereka bukan sifat? (Petunjuk: itu adalah pertanyaan jebakan.)Sekali lagi, di Scala, ciri-ciri disusun melalui linierisasi; jika kelas
A
memperluas ciriX
- ciri danY
, maka urutan di manaX
danY
dicampur menentukan bagaimana konflik antaraX
danY
diselesaikan. Di Java, mekanisme linierisasi ini tidak ada (sebagian ditolak karena terlalu "tidak mirip Java".)Alasan terdekat untuk menambahkan metode default ke antarmuka adalah untuk mendukung evolusi antarmuka , tetapi kami sangat menyadari bahwa kami melampaui itu. Apakah Anda menganggap itu sebagai "evolusi antarmuka ++" atau "sifat--" adalah masalah interpretasi pribadi. Jadi, untuk menjawab pertanyaan Anda tentang keselamatan ... selama Anda tetap berpegang pada apa yang sebenarnya didukung oleh mekanisme tersebut, daripada mencoba meregangkannya ke sesuatu yang tidak didukungnya, Anda akan baik-baik saja.
Tujuan desain utama adalah bahwa, dari perspektif klien antarmuka, metode default harus dibedakan dari metode antarmuka "biasa". Default-an suatu metode, oleh karena itu, hanya menarik bagi perancang dan pelaksana antarmuka.
Berikut beberapa kasus penggunaan yang sesuai dengan tujuan desain:
Evolusi antarmuka. Di sini, kami menambahkan metode baru ke antarmuka yang ada, yang memiliki implementasi default yang masuk akal dalam kaitannya dengan metode yang ada pada antarmuka itu. Contohnya adalah menambahkan
forEach
metode keCollection
, di mana implementasi default ditulis dalam istilahiterator()
metode.Metode "opsional". Di sini, perancang antarmuka mengatakan "Pelaksana tidak perlu mengimplementasikan metode ini jika mereka bersedia untuk hidup dengan keterbatasan dalam fungsionalitas yang diperlukan". Misalnya,
Iterator.remove
diberi default yang melemparUnsupportedOperationException
; karena sebagian besar implementasiIterator
memiliki perilaku ini, default membuat metode ini pada dasarnya opsional. (Jika perilaku dariAbstractCollection
diekspresikan sebagai default padaCollection
, kita mungkin melakukan hal yang sama untuk metode mutatif.)Metode kenyamanan. Ini adalah metode yang hanya untuk kenyamanan, sekali lagi umumnya diimplementasikan dalam istilah metode non-default di kelas. The
logger()
metode dalam contoh pertama Anda adalah ilustrasi yang wajar ini.Kombinator. Ini adalah metode komposisi yang membuat instance baru dari antarmuka berdasarkan instance saat ini. Misalnya metode
Predicate.and()
atauComparator.thenComparing()
contoh kombinator.Jika Anda memberikan implementasi default, Anda juga harus memberikan beberapa spesifikasi untuk default (di JDK, kami menggunakan
@implSpec
tag javadoc untuk ini) untuk membantu pelaksana dalam memahami apakah mereka ingin mengganti metode atau tidak. Beberapa default, seperti metode kemudahan dan kombinator, hampir tidak pernah diganti; yang lain, seperti metode opsional, sering diganti. Anda perlu memberikan spesifikasi yang cukup (bukan hanya dokumentasi) tentang apa yang dijanjikan default untuk dilakukan, sehingga implementor dapat membuat keputusan yang masuk akal tentang apakah mereka perlu menimpanya.sumber
MouseListener
? Sejauh gaya API ini masuk akal, ini cocok dengan keranjang "metode opsional". Pastikan untuk mendokumentasikan opsional-an dengan jelas!MouseListener
. Terima kasih atas tanggapannya.