Apakah bahasa Jawa memiliki fitur delegasi, mirip dengan bagaimana C # memiliki dukungan untuk delegasi?
Apakah bahasa Jawa memiliki fitur delegasi, mirip dengan bagaimana C # memiliki dukungan untuk delegasi?
Jawaban:
Tidak juga, tidak.
Anda mungkin dapat mencapai efek yang sama dengan menggunakan refleksi untuk mendapatkan objek Metode yang dapat Anda panggil, dan cara lain adalah membuat antarmuka dengan metode 'pemanggilan' atau 'eksekusi' tunggal, dan kemudian instantiate mereka untuk memanggil metode Anda tertarik (yaitu menggunakan kelas batin anonim).
Anda mungkin juga menemukan artikel ini menarik / berguna: Programmer Java Melihat C # Delegate (@ archive.org)
Bergantung tepat apa yang Anda maksud, Anda dapat mencapai efek yang sama (melewati metode) menggunakan Pola Strategi.
Alih-alih baris seperti ini yang menyatakan tanda tangan metode bernama:
// C#
public delegate void SomeFunction();
mendeklarasikan antarmuka:
// Java
public interface ISomeBehaviour {
void SomeFunction();
}
Untuk implementasi konkret dari metode ini, tentukan kelas yang mengimplementasikan perilaku:
// Java
public class TypeABehaviour implements ISomeBehaviour {
public void SomeFunction() {
// TypeA behaviour
}
}
public class TypeBBehaviour implements ISomeBehaviour {
public void SomeFunction() {
// TypeB behaviour
}
}
Maka di mana pun Anda memiliki SomeFunction
delegasi dalam C #, gunakan ISomeBehaviour
referensi sebagai gantinya:
// C#
SomeFunction doSomething = SomeMethod;
doSomething();
doSomething = SomeOtherMethod;
doSomething();
// Java
ISomeBehaviour someBehaviour = new TypeABehaviour();
someBehaviour.SomeFunction();
someBehaviour = new TypeBBehaviour();
someBehaviour.SomeFunction();
Dengan kelas dalam anonim, Anda bahkan dapat menghindari mendeklarasikan kelas bernama terpisah dan hampir memperlakukannya seperti fungsi delegasi nyata.
// Java
public void SomeMethod(ISomeBehaviour pSomeBehaviour) {
...
}
...
SomeMethod(new ISomeBehaviour() {
@Override
public void SomeFunction() {
// your implementation
}
});
Ini mungkin hanya boleh digunakan ketika implementasi sangat spesifik untuk konteks saat ini dan tidak akan mendapat manfaat dari digunakan kembali.
Dan tentu saja di Jawa 8, ini pada dasarnya menjadi ekspresi lambda:
// Java 8
SomeMethod(() -> { /* your implementation */ });
pengantar
Versi terbaru dari lingkungan pengembangan Microsoft Visual J ++ mendukung konstruksi bahasa yang disebut delegasi atau referensi metode terikat . Konstruk ini, dan kata kunci baru
delegate
danmulticast
diperkenalkan untuk mendukungnya, bukan bagian dari bahasa pemrograman Java TM , yang ditentukan oleh Spesifikasi Bahasa Jawa dan diubah oleh Spesifikasi Kelas Batin yang disertakan dalam dokumentasi untuk perangkat lunak JDKTM 1.1 .Sepertinya bahasa pemrograman Java tidak akan menyertakan konstruk ini. Sun sudah mempertimbangkan untuk mengadopsi itu pada tahun 1996, sejauh membangun dan membuang prototipe kerja. Kesimpulan kami adalah bahwa referensi metode terikat tidak perlu dan merugikan bahasa. Keputusan ini dibuat berdasarkan konsultasi dengan Borland International, yang memiliki pengalaman sebelumnya dengan referensi metode terikat dalam Delphi Object Pascal.
Kami percaya referensi metode terikat tidak diperlukan karena alternatif desain lain, kelas dalam , menyediakan fungsionalitas yang sama atau unggul. Secara khusus, kelas dalam sepenuhnya mendukung persyaratan penanganan acara antarmuka pengguna, dan telah digunakan untuk mengimplementasikan API antarmuka pengguna setidaknya sekomprehensif Windows Foundation Classes.
Kami percaya referensi metode terikat berbahaya karena mengurangi kesederhanaan bahasa pemrograman Java dan karakter yang berorientasi objek secara luas dari API. Referensi metode Bound juga memperkenalkan penyimpangan ke dalam sintaksis bahasa dan aturan pelingkupan. Akhirnya, mereka mencairkan investasi dalam teknologi VM karena VM diharuskan untuk menangani jenis referensi tambahan dan berbeda dan hubungan metode secara efisien.
Sudahkah Anda membaca ini :
Delegasi adalah konstruk yang berguna dalam sistem berbasis acara. Delegasi pada dasarnya adalah objek yang menyandikan metode pengiriman pada objek tertentu. Dokumen ini menunjukkan bagaimana kelas dalam java menyediakan solusi yang lebih umum untuk masalah seperti itu.
Apa itu Delegasi? Benar-benar sangat mirip dengan fungsi pointer ke anggota seperti yang digunakan dalam C ++. Tapi seorang delegasi berisi objek target beserta metode yang akan dipanggil. Idealnya akan menyenangkan untuk mengatakan:
obj.registerHandler (ano.methodOne);
..dan metode methodOne akan dipanggil pada ano ketika beberapa peristiwa tertentu diterima.
Inilah yang dicapai oleh struktur Delegasi.
Kelas Dalam Jawa
Telah diperdebatkan bahwa Java menyediakan fungsionalitas ini melalui kelas-kelas dalam anonim dan dengan demikian tidak memerlukan konstruksi Delegasi tambahan.
obj.registerHandler(new Handler() {
public void handleIt(Event ev) {
methodOne(ev);
}
} );
Pada pandangan pertama ini tampaknya benar tetapi pada saat yang sama merupakan gangguan. Karena untuk banyak contoh pemrosesan acara, kesederhanaan sintaksis Delegasi sangat menarik.
General Handler
Namun, jika pemrograman berbasis peristiwa digunakan dengan cara yang lebih luas, katakanlah, misalnya, sebagai bagian dari lingkungan pemrograman asinkron umum, ada lebih banyak yang dipertaruhkan.
Dalam situasi umum seperti itu, tidak cukup hanya menyertakan metode target dan instance objek target. Secara umum mungkin ada parameter lain yang diperlukan, yang ditentukan dalam konteks ketika event handler terdaftar.
Dalam situasi yang lebih umum ini, pendekatan java dapat memberikan solusi yang sangat elegan, terutama jika dikombinasikan dengan penggunaan variabel final:
void processState(final T1 p1, final T2 dispatch) {
final int a1 = someCalculation();
m_obj.registerHandler(new Handler() {
public void handleIt(Event ev) {
dispatch.methodOne(a1, ev, p1);
}
} );
}
final * final * final
Mendapat perhatian Anda?
Perhatikan bahwa variabel terakhir dapat diakses dari dalam definisi metode kelas anonim. Pastikan untuk mempelajari kode ini dengan cermat untuk memahami akibatnya. Ini berpotensi merupakan teknik yang sangat kuat. Misalnya, ini dapat digunakan untuk efek yang baik ketika mendaftarkan penangan di MiniDOM dan dalam situasi yang lebih umum.
Sebaliknya, konstruksi Delegasi tidak memberikan solusi untuk persyaratan yang lebih umum ini, dan karenanya harus ditolak sebagai idiom yang menjadi dasar desain.
Saya tahu posting ini sudah tua, tetapi Java 8 telah menambahkan lambdas, dan konsep antarmuka fungsional, yang merupakan antarmuka dengan hanya satu metode. Bersama-sama ini menawarkan fungsionalitas yang mirip dengan delegasi C #. Lihat di sini untuk info lebih lanjut, atau cukup google Java Lambdas. http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-final.html
Tidak, tetapi mereka dapat dipalsukan menggunakan proxy dan refleksi:
public static class TestClass {
public String knockKnock() {
return "who's there?";
}
}
private final TestClass testInstance = new TestClass();
@Test public void
can_delegate_a_single_method_interface_to_an_instance() throws Exception {
Delegator<TestClass, Callable<String>> knockKnockDelegator = Delegator.ofMethod("knockKnock")
.of(TestClass.class)
.to(Callable.class);
Callable<String> callable = knockKnockDelegator.delegateTo(testInstance);
assertThat(callable.call(), is("who's there?"));
}
Hal yang menyenangkan tentang idiom ini adalah Anda dapat memverifikasi bahwa metode yang didelegasikan-ke ada, dan memiliki tanda tangan yang diperlukan, pada titik di mana Anda membuat delegator (walaupun tidak pada waktu kompilasi, sayangnya, meskipun plug-in FindBugs mungkin bantu di sini), lalu gunakan dengan aman untuk mendelegasikan ke berbagai kejadian.
Lihat kode karg di github untuk tes dan implementasi lebih lanjut .
Saya telah menerapkan dukungan panggilan balik / delegasi di Jawa menggunakan refleksi. Detail dan sumber kerja tersedia di situs web saya .
Ada kelas prinsip bernama Callback dengan kelas bersarang bernama WithParms. API yang membutuhkan callback akan mengambil objek Callback sebagai parameter dan, jika perlu, membuat Callback. WithParms sebagai variabel metode. Karena banyak sekali aplikasi objek ini akan bersifat rekursif, ini bekerja dengan sangat bersih.
Dengan kinerja yang masih merupakan prioritas tinggi bagi saya, saya tidak ingin diharuskan untuk membuat array objek sekali pakai untuk menyimpan parameter untuk setiap doa - setelah semua dalam struktur data besar mungkin ada ribuan elemen, dan dalam pemrosesan pesan skenario kita akhirnya bisa memproses ribuan struktur data per detik.
Untuk menjadi threadsafe, array parameter harus ada secara unik untuk setiap pemanggilan metode API, dan untuk efisiensi yang sama harus digunakan untuk setiap pemanggilan callback; Saya membutuhkan objek kedua yang akan lebih murah untuk dibuat untuk mengikat panggilan balik dengan array parameter untuk doa. Tetapi, dalam beberapa skenario, penyerang akan sudah memiliki array parameter karena alasan lain. Karena dua alasan ini, array parameter tidak termasuk dalam objek Callback. Juga pilihan doa (melewati parameter sebagai array atau sebagai objek individual) berada di tangan API menggunakan panggilan balik yang memungkinkannya untuk menggunakan doa mana saja yang paling cocok untuk pekerjaan bagian dalamnya.
Kelas bersarang WithParms, kemudian, adalah opsional dan melayani dua tujuan, ini berisi array objek parameter yang diperlukan untuk panggilan balik, dan menyediakan 10 metode pemanggilan () yang berlebihan (dengan dari 1 hingga 10 parameter) yang memuat array parameter dan kemudian aktifkan target panggilan balik.
Berikut ini adalah contoh menggunakan panggilan balik untuk memproses file dalam pohon direktori. Ini adalah pass validasi awal yang hanya menghitung file untuk diproses dan memastikan tidak ada yang melebihi ukuran maksimum yang telah ditentukan. Dalam hal ini kami hanya membuat panggilan balik sesuai dengan permintaan API. Namun, kami mencerminkan metode target sebagai nilai statis sehingga refleksi tidak dilakukan setiap waktu.
static private final Method COUNT =Callback.getMethod(Xxx.class,"callback_count",true,File.class,File.class);
...
IoUtil.processDirectory(root,new Callback(this,COUNT),selector);
...
private void callback_count(File dir, File fil) {
if(fil!=null) { // file is null for processing a directory
fileTotal++;
if(fil.length()>fileSizeLimit) {
throw new Abort("Failed","File size exceeds maximum of "+TextUtil.formatNumber(fileSizeLimit)+" bytes: "+fil);
}
}
progress("Counting",dir,fileTotal);
}
IoUtil.processDirectory ():
/**
* Process a directory using callbacks. To interrupt, the callback must throw an (unchecked) exception.
* Subdirectories are processed only if the selector is null or selects the directories, and are done
* after the files in any given directory. When the callback is invoked for a directory, the file
* argument is null;
* <p>
* The callback signature is:
* <pre> void callback(File dir, File ent);</pre>
* <p>
* @return The number of files processed.
*/
static public int processDirectory(File dir, Callback cbk, FileSelector sel) {
return _processDirectory(dir,new Callback.WithParms(cbk,2),sel);
}
static private int _processDirectory(File dir, Callback.WithParms cbk, FileSelector sel) {
int cnt=0;
if(!dir.isDirectory()) {
if(sel==null || sel.accept(dir)) { cbk.invoke(dir.getParent(),dir); cnt++; }
}
else {
cbk.invoke(dir,(Object[])null);
File[] lst=(sel==null ? dir.listFiles() : dir.listFiles(sel));
if(lst!=null) {
for(int xa=0; xa<lst.length; xa++) {
File ent=lst[xa];
if(!ent.isDirectory()) {
cbk.invoke(dir,ent);
lst[xa]=null;
cnt++;
}
}
for(int xa=0; xa<lst.length; xa++) {
File ent=lst[xa];
if(ent!=null) { cnt+=_processDirectory(ent,cbk,sel); }
}
}
}
return cnt;
}
Contoh ini menggambarkan keindahan dari pendekatan ini - logika spesifik aplikasi diabstraksi ke dalam callback, dan kesulitan berjalan secara rekursif pohon direktori terselip dengan baik dalam metode utilitas statis yang sepenuhnya dapat digunakan kembali. Dan kita tidak harus berulang kali membayar harga untuk mendefinisikan dan mengimplementasikan antarmuka untuk setiap penggunaan baru. Tentu saja, argumen untuk antarmuka adalah bahwa itu jauh lebih eksplisit tentang apa yang harus diterapkan (itu ditegakkan, tidak hanya didokumentasikan) - tetapi dalam praktiknya saya belum menemukan itu menjadi masalah untuk mendapatkan definisi panggilan balik dengan benar.
Mendefinisikan dan mengimplementasikan antarmuka tidak terlalu buruk (kecuali Anda mendistribusikan applet, seperti saya, di mana menghindari membuat kelas tambahan sebenarnya penting), tetapi di mana ini benar-benar bersinar adalah ketika Anda memiliki beberapa callback dalam satu kelas. Tidak hanya dipaksa untuk mendorong mereka masing-masing ke kelas dalam yang ditambahkan tambahan overhead dalam aplikasi dikerahkan, tetapi itu benar-benar membosankan untuk program dan semua kode boiler-plate benar-benar hanya "noise".
Ya & Tidak, tetapi pola pendelegasian di Jawa dapat dipikirkan dengan cara ini. Video tutorial ini adalah tentang pertukaran data antara aktivitas - fragmen, dan memiliki esensi besar pola penyerahan delegasi menggunakan antarmuka.
Itu tidak memiliki delegate
kata kunci eksplisit sebagai C #, tetapi Anda dapat mencapai yang serupa di Java 8 dengan menggunakan antarmuka fungsional (yaitu setiap antarmuka dengan tepat satu metode) dan lambda:
private interface SingleFunc {
void printMe();
}
public static void main(String[] args) {
SingleFunc sf = () -> {
System.out.println("Hello, I am a simple single func.");
};
SingleFunc sfComplex = () -> {
System.out.println("Hello, I am a COMPLEX single func.");
};
delegate(sf);
delegate(sfComplex);
}
private static void delegate(SingleFunc f) {
f.printMe();
}
Setiap objek tipe baru SingleFunc
harus diimplementasikan printMe()
, sehingga aman untuk meneruskannya ke metode lain (misalnya delegate(SingleFunc)
) untuk memanggil printMe()
metode tersebut.
Meskipun tidak ada yang bersih, tetapi Anda bisa mengimplementasikan sesuatu seperti delegasi C # menggunakan Java Proxy .
Tidak, tetapi memiliki perilaku serupa, secara internal.
Dalam C # delegasi digunakan untuk membuat titik entri yang terpisah dan mereka bekerja seperti penunjuk fungsi.
Di java tidak ada hal sebagai penunjuk fungsi (pada tampilan atas) tetapi secara internal Java perlu melakukan hal yang sama untuk mencapai tujuan ini.
Misalnya, membuat utas di Java memerlukan kelas yang memperpanjang Utas atau menerapkan Runnable, karena variabel objek kelas dapat digunakan sebagai penunjuk lokasi memori.
Tidak, Java tidak memiliki fitur luar biasa itu. Tapi Anda bisa membuatnya secara manual menggunakan pola pengamat. Berikut ini sebuah contoh: Tulis delegasi C # di java
Kode yang dijelaskan menawarkan banyak keuntungan dari delegasi C #. Metode, baik statis atau dinamis, dapat diperlakukan secara seragam. Kompleksitas dalam metode panggilan melalui refleksi berkurang dan kode dapat digunakan kembali, dalam arti tidak memerlukan kelas tambahan dalam kode pengguna. Catatan kami sedang memanggil versi kenyamanan alternatif dari invoke, di mana metode dengan satu parameter dapat dipanggil tanpa membuat array objek. Kode Java di bawah ini:
class Class1 {
public void show(String s) { System.out.println(s); }
}
class Class2 {
public void display(String s) { System.out.println(s); }
}
// allows static method as well
class Class3 {
public static void staticDisplay(String s) { System.out.println(s); }
}
public class TestDelegate {
public static final Class[] OUTPUT_ARGS = { String.class };
public final Delegator DO_SHOW = new Delegator(OUTPUT_ARGS,Void.TYPE);
public void main(String[] args) {
Delegate[] items = new Delegate[3];
items[0] = DO_SHOW .build(new Class1(),"show,);
items[1] = DO_SHOW.build (new Class2(),"display");
items[2] = DO_SHOW.build(Class3.class, "staticDisplay");
for(int i = 0; i < items.length; i++) {
items[i].invoke("Hello World");
}
}
}
Java tidak memiliki delegasi dan bangga karenanya :). Dari apa yang saya baca di sini saya menemukan dua cara intinya untuk delegasi palsu: 1. refleksi; 2. kelas batin
Pantulannya slooooow! Kelas dalam tidak mencakup fungsi use-case: sort yang paling sederhana. Tidak ingin masuk ke detail, tetapi solusi dengan kelas dalam pada dasarnya adalah membuat kelas pembungkus untuk array bilangan bulat untuk diurutkan dalam urutan naik dan kelas untuk array bilangan bulat untuk diurutkan dalam urutan menurun.