Apa yang mereka maksud dengan pola desain acara?
Mereka kemungkinan besar merujuk pada implementasi dari pola pengamat yang merupakan konstruksi bahasa inti dalam C #, diekspos sebagai ' peristiwa '. Mendengarkan acara dimungkinkan dengan mengaitkan seorang delegasi dengan mereka. Seperti yang ditunjukkan Yam Marcovic, EventHandler
adalah tipe delegasi basis konvensional untuk acara, tetapi tipe delegasi apa pun dapat digunakan.
Bagaimana komposisi ini menjadi mudah jika delegasi digunakan?
Ini mungkin hanya merujuk pada tawaran delegasi fleksibilitas. Anda dapat dengan mudah 'menciptakan' perilaku tertentu. Dengan bantuan lambdas , sintaksis untuk melakukan ini juga sangat ringkas. Perhatikan contoh berikut.
class Bunny
{
Func<bool> _canHop;
public Bunny( Func<bool> canHop )
{
_canHop = canHop;
}
public void Hop()
{
if ( _canHop() ) Console.WriteLine( "Hop!" );
}
}
Bunny captiveBunny = new Bunny( () => IsBunnyReleased );
Bunny lazyBunny = new Bunny( () => !IsLazyDay );
Bunny captiveLazyBunny = new Bunny( () => IsBunnyReleased && !IsLazyDay );
Melakukan sesuatu yang mirip dengan antarmuka akan mengharuskan Anda untuk menggunakan pola strategi atau menggunakan Bunny
kelas dasar (abstrak) dari mana Anda memperluas kelinci yang lebih spesifik.
jika ada sekelompok metode terkait yang dapat dipanggil, maka gunakan antarmuka-Apa manfaatnya?
Sekali lagi, saya akan menggunakan kelinci untuk menunjukkan bagaimana itu akan lebih mudah.
interface IAnimal
{
void Jump();
void Eat();
void Poo();
}
class Bunny : IAnimal { ... }
class Chick : IAnimal { ... }
// Using the interface.
IAnimal bunny = new Bunny();
bunny.Jump(); bunny.Eat(); bunny.Poo();
IAnimal chick = new Chick();
chick.Jump(); chick.Eat(); chick.Poo();
// Without the interface.
Action bunnyJump = () => bunny.Jump();
Action bunnyEat = () => bunny.Eat();
Action bunnyPoo = () => bunny.Poo();
bunnyJump(); bunnyEat(); bunnyPoo();
Action chickJump = () => chick.Jump();
Action chickEat = () => chick.Eat();
...
jika sebuah kelas hanya membutuhkan satu implementasi dari metode ini, gunakan antarmuka-bagaimana itu dibenarkan dalam hal manfaat?
Untuk ini, perhatikan contoh pertama dengan kelinci lagi. Jika hanya satu implementasi yang diperlukan - tidak ada komposisi khusus yang diperlukan -, Anda dapat mengekspos perilaku ini sebagai antarmuka. Anda tidak perlu membangun lambdas, Anda hanya dapat menggunakan antarmuka.
Kesimpulan
Delegasi menawarkan lebih banyak fleksibilitas, sementara antarmuka membantu Anda membuat kontrak yang kuat. Oleh karena itu saya menemukan poin terakhir yang disebutkan, "Kelas mungkin membutuhkan lebih dari satu implementasi metode." , sejauh ini yang paling relevan.
Alasan tambahan kapan harus menggunakan delegasi adalah ketika Anda ingin mengekspos hanya bagian dari kelas yang tidak dapat Anda sesuaikan dengan file sumbernya.
Sebagai contoh skenario seperti itu (fleksibilitas maksimum, tidak perlu memodifikasi sumber), pertimbangkan penerapan algoritma pencarian biner ini untuk kemungkinan pengumpulan dengan hanya melewati dua delegasi.
1) Pola acara, yah klasiknya adalah pola Pengamat, inilah tautan Microsoft yang bagus Pengamat bicara Microsoft
Artikel yang Anda tautkan tidak ditulis dengan sangat baik dan membuat hal-hal lebih rumit daripada yang diperlukan. Bisnis statis adalah akal sehat, Anda tidak dapat mendefinisikan antarmuka dengan anggota statis, jadi jika Anda ingin perilaku polimorfik pada metode statis, Anda akan menggunakan delegasi.
Tautan di atas berbicara tentang delegasi dan mengapa ada komposisi yang bagus, sehingga dapat membantu dengan permintaan Anda.
sumber
Pertama-tama, pertanyaan yang bagus. Saya mengagumi fokus Anda pada utilitas daripada menerima "praktik terbaik" secara membuta. +1 untuk itu.
Saya sudah membaca panduan itu sebelumnya. Anda harus mengingat sesuatu tentang hal itu - itu hanya panduan, terutama untuk pendatang C # yang tahu cara memprogram tetapi tidak begitu akrab dengan cara C # dalam melakukan sesuatu. Ini bukan halaman aturan, melainkan halaman yang menjelaskan bagaimana hal-hal sudah biasa dilakukan. Dan karena mereka sudah melakukan hal ini di mana-mana, mungkin ide yang bagus untuk tetap konsisten.
Saya akan langsung ke intinya, menjawab pertanyaan Anda.
Pertama-tama, saya anggap Anda sudah tahu apa antarmuka itu. Adapun delegasi, itu cukup untuk mengatakan bahwa itu adalah struktur yang mengandung pointer yang diketik ke metode, bersama dengan pointer opsional ke objek yang mewakili
this
argumen untuk metode itu. Dalam hal metode statis, penunjuk terakhir adalah nol.Ada juga delegasi Multicast, yang sama seperti delegasi, tetapi mungkin memiliki beberapa struktur yang ditugaskan untuk mereka (artinya panggilan tunggal untuk Memohon pada delegasi multicast memanggil semua metode dalam daftar permintaan yang ditugaskan).
Apa yang mereka maksud dengan pola desain acara?
Maksudnya menggunakan acara dalam C # (yang memiliki kata kunci khusus untuk menerapkan pola yang sangat berguna ini dengan canggih). Acara di C # didorong oleh delegasi multicast.
Saat Anda menentukan suatu peristiwa, seperti dalam contoh ini:
Compiler sebenarnya mengubah ini menjadi kode berikut:
Anda kemudian berlangganan ke suatu acara dengan melakukan
Yang mengkompilasi ke
Jadi itu terjadi di C # (atau. NET secara umum).
Bagaimana komposisi ini menjadi mudah jika delegasi digunakan?
Ini dapat dengan mudah ditunjukkan:
Misalkan Anda memiliki kelas yang bergantung pada serangkaian tindakan yang akan diteruskan ke sana. Anda bisa merangkum tindakan-tindakan itu dalam sebuah antarmuka:
Dan siapa pun yang ingin memberikan tindakan ke kelas Anda pertama-tama harus mengimplementasikan antarmuka itu. Atau Anda bisa membuat hidup mereka lebih mudah dengan bergantung pada kelas berikut:
Dengan cara ini, penelepon hanya perlu membuat instance dari RequiredMethods dan mengikat metode kepada delegasi saat runtime. Ini adalah biasanya lebih mudah.
Cara melakukan hal-hal ini sangat bermanfaat dalam keadaan yang tepat. Pikirkan tentang hal ini - mengapa bergantung pada antarmuka saat semua yang Anda benar-benar pedulikan adalah penerapannya diberikan kepada Anda?
Manfaat menggunakan antarmuka saat ada sekelompok metode terkait
Ini bermanfaat untuk menggunakan antarmuka karena antarmuka biasanya memerlukan implementasi waktu kompilasi eksplisit. Ini artinya Anda membuat kelas baru.
Dan jika Anda memiliki sekelompok metode terkait dalam satu paket, sebaiknya paket itu dapat digunakan kembali oleh bagian lain dari kode. Jadi jika mereka dapat membuat instantiate sebuah kelas daripada membangun sekumpulan delegasi, itu lebih mudah.
Manfaat menggunakan antarmuka jika suatu kelas hanya membutuhkan satu implementasi
Seperti disebutkan sebelumnya, antarmuka diimplementasikan dalam waktu kompilasi - yang berarti mereka lebih efisien daripada memanggil delegasi (yang merupakan tingkat tipuan per se).
"Satu implementasi" mungkin berarti implementasi yang ada di satu tempat yang terdefinisi dengan baik.
Kalau tidak, suatu implementasi mungkin datang dari mana saja dalam program yang kebetulan sesuai dengan metode tanda tangan. Itu memungkinkan lebih banyak fleksibilitas, karena metode hanya perlu menyesuaikan diri dengan tanda tangan yang diharapkan, daripada menjadi bagian dari kelas yang secara eksplisit mengimplementasikan antarmuka tertentu. Tetapi fleksibilitas itu mungkin harus dibayar mahal, dan benar-benar melanggar prinsip Pergantian Liskov , karena seringkali Anda menginginkan kesaksian, karena meminimalkan peluang terjadinya kecelakaan. Sama seperti Pengetikan Statis.
Istilah ini juga merujuk pada delegasi multicast di sini. Metode yang dideklarasikan oleh antarmuka hanya dapat diimplementasikan satu kali dalam kelas pelaksana. Tetapi delegasi dapat mengakumulasikan banyak metode, yang akan dipanggil secara berurutan.
Jadi semuanya, sepertinya panduan ini tidak cukup informatif, dan hanya berfungsi seperti apa - panduan, bukan buku aturan. Beberapa saran mungkin terdengar agak kontradiktif. Terserah Anda untuk memutuskan kapan tepat untuk menerapkan apa. Panduan ini sepertinya hanya memberi kita jalan umum.
Saya harap pertanyaan Anda telah dijawab untuk kepuasan Anda. Dan sekali lagi, pujian untuk pertanyaan itu.
sumber
Jika memori saya. NET masih berlaku, delegasi pada dasarnya adalah ptr fungsi atau functor. Itu menambahkan lapisan tipuan ke panggilan fungsi sehingga fungsi dapat diganti tanpa kode panggilan harus berubah. Ini adalah hal yang sama dengan antarmuka, kecuali bahwa suatu paket memaketkan beberapa fungsi secara bersamaan, dan seorang implementor harus mengimplementasikannya bersama-sama.
Pola acara, secara umum, adalah pola di mana sesuatu merespons peristiwa dari tempat lain (seperti pesan Windows). Serangkaian acara biasanya berakhir terbuka, mereka dapat datang dalam urutan apa pun, dan tidak harus saling terkait. Delegasi bekerja dengan baik untuk ini di mana setiap peristiwa dapat memanggil fungsi tunggal tanpa perlu referensi ke serangkaian objek implementasi yang mungkin juga mengandung banyak fungsi yang tidak relevan. Selain itu (ini adalah di mana memori .NET saya tidak jelas), saya pikir beberapa delegasi dapat dilampirkan ke suatu acara.
Pengomposisian, meskipun saya tidak terlalu mengenal istilah ini, pada dasarnya mendesain satu objek untuk memiliki beberapa sub-bagian, atau anak-anak agregat yang pekerjaannya diturunkan. Delegasi memungkinkan anak-anak untuk dicampur dan dicocokkan dengan cara yang lebih ad-hoc di mana antarmuka mungkin berlebihan atau menyebabkan terlalu banyak kopling dan kekakuan dan kerapuhan yang menyertainya.
Manfaat antarmuka untuk metode terkait adalah bahwa metode tersebut dapat berbagi keadaan objek pelaksana. Mendelegasikan fungsi tidak dapat membagikan, atau bahkan memuat, dengan rapi.
Jika suatu kelas membutuhkan implementasi tunggal, sebuah antarmuka lebih cocok karena di dalam setiap kelas yang mengimplementasikan seluruh koleksi, hanya satu implementasi yang dapat dilakukan, dan Anda mendapatkan manfaat dari kelas pelaksana (negara, enkapsulasi, dll.). Jika implementasi mungkin berubah karena keadaan runtime, delegasi bekerja lebih baik karena mereka dapat ditukar dengan implementasi lain tanpa mempengaruhi metode lain. Misalnya, jika ada tiga delegasi yang masing-masing memiliki dua implementasi yang mungkin, Anda akan membutuhkan delapan kelas yang berbeda mengimplementasikan antarmuka tiga metode untuk menjelaskan semua kemungkinan kombinasi negara.
sumber
Pola desain "acara" (lebih dikenal sebagai Pola Pengamat) memungkinkan Anda untuk melampirkan beberapa metode tanda tangan yang sama ke delegasi. Anda tidak dapat melakukannya dengan antarmuka.
Saya sama sekali tidak yakin bahwa komposisi lebih mudah untuk delegasi daripada antarmuka. Itu pernyataan yang sangat aneh. Saya ingin tahu apakah maksudnya karena Anda dapat melampirkan metode anonim ke delegasi.
sumber
Klarifikasi terbesar yang dapat saya tawarkan:
Begitu:
sumber
Pertanyaan Anda tentang acara telah dibahas dengan baik. Dan juga benar, bahwa sebuah antarmuka dapat mendefinisikan beberapa metode (tetapi sebenarnya tidak perlu), sementara tipe fungsi hanya pernah menempatkan kendala pada fungsi individu.
Perbedaan sesungguhnya adalah:
Tentu, tapi apa artinya ini?
Mari kita ambil contoh ini (kode dalam haXe karena C # saya tidak terlalu baik):
Sekarang metode filter memudahkan untuk dengan mudah melewati hanya sepotong kecil logika, yang tidak mengetahui organisasi internal koleksi, sedangkan koleksi tidak bergantung pada logika yang diberikan kepadanya. Besar. Kecuali untuk satu masalah:
Koleksi tidak bergantung pada logika. Koleksi secara inheren membuat asumsi, bahwa fungsi yang diteruskan dirancang untuk menguji nilai terhadap suatu kondisi dan mengembalikan keberhasilan tes. Perhatikan bahwa tidak semua fungsi, yang mengambil satu nilai sebagai argumen dan mengembalikan boolean sebenarnya hanyalah predikat. Misalnya metode hapus koleksi kami adalah fungsi seperti itu.
Anggaplah kita menelepon
c.filter(c.remove)
. Hasilnya akan menjadi koleksi dengan semua elemenc
sementarac
itu sendiri menjadi kosong. Ini sangat disayangkan, karena secara alami kita akan mengharapkanc
dirinya menjadi invarian.Contohnya sangat dibangun. Tetapi masalah utama adalah, bahwa pemanggilan kode
c.filter
dengan beberapa nilai fungsi sebagai argumen tidak memiliki cara untuk mengetahui apakah argumen itu cocok (yaitu pada akhirnya akan menghemat invarian). Kode yang menciptakan nilai fungsi mungkin atau mungkin tidak tahu, bahwa itu akan ditafsirkan sebagai predikat.Sekarang mari kita ubah beberapa hal:
Apa yang sudah berubah? Apa yang telah berubah adalah, bahwa nilai apa pun yang sekarang diberikan
filter
telah secara eksplisit menandatangani kontrak menjadi predikat. Tentu saja programmer jahat atau sangat bodoh membuat implementasi dari antarmuka yang tidak bebas efek samping dan karenanya bukan predikat.Tetapi yang tidak bisa lagi terjadi adalah seseorang mengikat unit logis dari data / kode, yang secara keliru diartikan sebagai predikat karena struktur luarnya.
Jadi ulangi apa yang dikatakan di atas hanya dalam beberapa kata:
Keuntungan dari hubungan eksplisit adalah, bahwa Anda dapat memastikannya. Kerugiannya adalah, bahwa mereka membutuhkan overhead dari kesederhanaan. Sebaliknya, kerugian dari hubungan implisit (dalam kasus kami satu fungsi tanda tangan cocok dengan tanda tangan yang diinginkan), adalah bahwa Anda tidak dapat benar-benar 100% yakin bahwa Anda dapat menggunakan sesuatu dengan cara ini. Keuntungannya adalah, Anda bisa menjalin hubungan tanpa semua overhead. Anda dapat dengan cepat melempar barang-barang bersama, karena struktur mereka memungkinkan. Itulah yang dimaksud komposisi mudah.
Ini agak seperti LEGO: Anda dapat dengan mudah memasang figur star wars LEGO ke kapal bajak laut LEGO, hanya karena struktur luar memungkinkannya. Sekarang Anda mungkin merasa itu sangat salah, atau mungkin persis seperti yang Anda inginkan. Tidak ada yang akan menghentikan Anda.
sumber
int IList.Count { get { ... } }
) atau secara implisit (public int Count { get { ... } }
). Perbedaan ini tidak relevan dengan diskusi ini, tetapi patut disebutkan untuk menghindari pembaca yang membingungkan.sumber