Saya memiliki antarmuka generik
public interface Consumer<E> {
public void consume(E e);
}
Saya memiliki kelas yang mengkonsumsi dua jenis objek, jadi saya ingin melakukan sesuatu seperti:
public class TwoTypesConsumer implements Consumer<Tomato>, Consumer<Apple>
{
public void consume(Tomato t) { ..... }
public void consume(Apple a) { ...... }
}
Rupanya saya tidak bisa melakukan itu.
Tentu saja saya dapat mengimplementasikan pengiriman sendiri, misalnya
public class TwoTypesConsumer implements Consumer<Object> {
public void consume(Object o) {
if (o instanceof Tomato) { ..... }
else if (o instanceof Apple) { ..... }
else { throw new IllegalArgumentException(...) }
}
}
Tapi saya mencari solusi pengecekan dan pengiriman tipe kompilasi yang disediakan generik.
Solusi terbaik yang dapat saya pikirkan adalah mendefinisikan antarmuka yang terpisah, misalnya
public interface AppleConsumer {
public void consume(Apple a);
}
Secara fungsional, solusi ini OK, saya pikir. Itu hanya verbose dan jelek.
Ada ide?
java
generics
interface
multiple-inheritance
daphshez
sumber
sumber
Jawaban:
Pertimbangkan enkapsulasi:
Jika membuat kelas dalam statis ini mengganggu Anda, Anda bisa menggunakan kelas anonim:
sumber
TwoTypesConsumer
memenuhi kontrak, jadi apa gunanya? Itu tidak dapat diteruskan ke metode yang menginginkan kedua jenis . Ide keseluruhan dari konsumen tipe dua adalah Anda dapat memberikannya pada metode yang menginginkan konsumen tomat dan juga metode yang menginginkan konsumen apel. Di sini kita tidak punya.Consumer
TwoTypesConsumer
instance terlampir jika perlu, dan kemudian Anda dapat meneruskantwoTypesConsumer.getAppleConsumer()
ke metode yang menginginkan konsumen apel. Pilihan lain adalah menambahkan metode yang miripaddConsumer(Producer<Apple> producer)
dengan TwoTypesConsumer.ExceptionMapper
) ...Karena penghapusan tipe, Anda tidak dapat mengimplementasikan antarmuka yang sama dua kali (dengan parameter tipe yang berbeda).
sumber
Inilah solusi yang mungkin didasarkan pada solusi Steve McLeod :
Persyaratan implisit dari pertanyaan itu adalah
Consumer<Tomato>
danConsumer<Apple>
benda-benda yang berbagi keadaan. Kebutuhan akanConsumer<Tomato>, Consumer<Apple>
objek berasal dari metode lain yang mengharapkan ini sebagai parameter. Saya membutuhkan satu kelas untuk mengimplementasikan keduanya agar dapat berbagi status.Ide Steve adalah menggunakan dua kelas batin, masing-masing menerapkan tipe generik yang berbeda.
Versi ini menambahkan getter untuk objek yang mengimplementasikan antarmuka konsumen, yang kemudian dapat diteruskan ke metode lain yang mengharapkannya.
sumber
Consumer<*>
instance di bidang instance jikaget*Consumer
sering dipanggil.Setidaknya, Anda dapat melakukan sedikit peningkatan pada implementasi pengiriman Anda dengan melakukan sesuatu seperti berikut:
Buah menjadi leluhur Tomat dan Apple.
sumber
hanya menemukan ini. Itu baru saja terjadi, bahwa saya memiliki Masalah yang sama, tetapi saya menyelesaikannya dengan cara yang berbeda: Saya baru saja membuat Antarmuka baru seperti ini
Sayangnya, ini dianggap
Consumer<A>
dan TIDAKConsumer<B>
bertentangan dengan semua Logika. Jadi, Anda harus membuat Adaptor kecil untuk konsumen kedua seperti ini di dalam kelas Andajika
Consumer<A>
diperlukan, Anda dapat dengan mudah lulusthis
, dan jikaConsumer<B>
diperlukan hanya lewatconsumerAdapter
sumber
Anda tidak dapat melakukan ini secara langsung dalam satu kelas karena definisi kelas di bawah ini tidak dapat dikompilasi karena penghapusan tipe generik dan deklarasi antarmuka duplikat.
Solusi lain untuk mengemas operasi konsumsi yang sama dalam satu kelas mengharuskan untuk mendefinisikan kelas Anda sebagai:
yang tidak ada gunanya karena Anda perlu mengulang / menduplikasi definisi dari kedua operasi dan mereka tidak akan dirujuk dari antarmuka. IMHO melakukan ini adalah duplikasi kecil dan kode yang buruk yang saya coba hindari.
Ini mungkin menjadi indikator juga bahwa ada terlalu banyak tanggung jawab dalam satu kelas untuk mengkonsumsi 2 objek yang berbeda (jika tidak digabungkan).
Namun apa yang saya lakukan dan apa yang dapat Anda lakukan adalah menambahkan objek pabrik eksplisit untuk membuat konsumen yang terhubung dengan cara berikut:
Jika pada kenyataannya tipe-tipe tersebut benar-benar digabungkan (terkait) maka saya akan merekomendasikan untuk membuat implementasi dengan cara seperti ini:
Keuntungannya adalah kelas pabrik mengetahui kedua implementasi, ada status bersama (jika diperlukan) dan Anda dapat mengembalikan lebih banyak konsumen yang digabungkan jika diperlukan. Tidak ada pernyataan metode konsumsi berulang yang tidak berasal dari antarmuka.
Harap dicatat bahwa setiap konsumen mungkin kelas independen (masih pribadi) jika mereka tidak sepenuhnya terkait.
Kelemahan dari solusi itu adalah kompleksitas kelas yang lebih tinggi (bahkan jika ini bisa menjadi file satu java) dan untuk mengakses metode konsumsi Anda memerlukan satu panggilan lagi jadi alih-alih:
kamu punya:
Untuk meringkas, Anda dapat mendefinisikan 2 konsumen umum dalam satu kelas tingkat atas menggunakan 2 kelas batin tetapi dalam kasus panggilan Anda harus mendapatkan pertama referensi ke konsumen pelaksana yang tepat karena ini tidak bisa hanya satu objek konsumen.
sumber
Dalam gaya Fungsional cukup mudah melakukan ini tanpa mengimplementasikan antarmuka dan juga melakukan pengecekan tipe waktu kompilasi.
Antarmuka fungsional kami untuk mengkonsumsi entitas
manajer kami untuk memproses dan mengkonsumsi entitas dengan tepat
sumber
Alternatif lain untuk menghindari penggunaan lebih banyak kelas. (contoh menggunakan java8 +)
sumber
Maaf untuk menjawab pertanyaan lama, tapi saya sangat menyukainya! Coba opsi ini:
Saya pikir itulah yang Anda cari.
Anda mendapatkan hasil ini:
sumber