Kami memiliki Aplikasi Web di mana kami memiliki banyak (> 50) komponen Web kecil yang berinteraksi satu sama lain.
Agar semuanya dipisahkan, kita memiliki aturan bahwa tidak ada komponen yang dapat langsung merujuk yang lain. Alih-alih, komponen mengaktifkan peristiwa yang kemudian (dalam aplikasi "utama") terhubung untuk memanggil metode komponen lain.
Seiring berjalannya waktu, semakin banyak komponen yang ditambahkan dan file aplikasi "utama" menjadi berserakan dengan potongan kode yang terlihat seperti ini:
buttonsToolbar.addEventListener('request-toggle-contact-form-modal', () => {
contactForm.toggle()
})
buttonsToolbar.addEventListener('request-toggle-bug-reporter-modal', () => {
bugReporter.toggle()
})
// ... etc
Untuk memperbaiki ini kami mengelompokkan fungsi yang sama bersama-sama, dalam Class
, beri nama itu sesuatu yang relevan, melewati elemen yang berpartisipasi ketika instantiating dan menangani "kabel" di dalam Class
, seperti:
class Contact {
constructor(contactForm, bugReporter, buttonsToolbar) {
this.contactForm = contactForm
this.bugReporterForm = bugReporterForm
this.buttonsToolbar = buttonsToolbar
this.buttonsToolbar
.addEventListener('request-toggle-contact-form-modal', () => {
this.toggleContactForm()
})
this.buttonsToolbar
.addEventListener('request-toggle-bug-reporter-modal', () => {
this.toggleBugReporterForm()
})
}
toggleContactForm() {
this.contactForm.toggle()
}
toggleBugReporterForm() {
this.bugReporterForm.toggle()
}
}
dan kami instantiate seperti:
<html>
<contact-form></contact-form>
<bug-reporter></bug-reporter>
<script>
const contact = new Contact(
document.querySelector('contact-form'),
document.querySelector('bug-form')
)
</script>
</html>
Saya benar-benar lelah memperkenalkan pola saya sendiri, terutama yang tidak benar-benar OOP-y karena saya gunakan Classes
sebagai wadah inisialisasi belaka, karena tidak ada kata yang lebih baik.
Apakah ada pola yang lebih baik / lebih dikenal untuk menangani jenis tugas yang saya lewatkan?
Jawaban:
Kode yang Anda miliki cukup bagus. Hal yang kelihatannya agak membingungkan adalah kode inisialisasi bukan bagian dari objek itu sendiri. Artinya, Anda dapat membuat instance objek, tetapi jika Anda lupa menyebut kelas kabelnya, itu tidak berguna.
Pertimbangkan Notification Center (alias Event Bus) yang mendefinisikan sesuatu seperti ini:
Ini adalah pengendali acara multi-pengiriman DIY. Anda kemudian dapat melakukan perkabelan Anda sendiri dengan hanya memerlukan NotificationCenter sebagai argumen konstruktor. Mengirim pesan ke dalamnya dan menunggunya memberi Anda muatan adalah satu-satunya kontak yang Anda miliki dengan sistem, jadi sangat SOLID.
Catatan: Saya menggunakan string literal di tempat untuk kunci agar konsisten dengan gaya yang digunakan dalam pertanyaan dan untuk kesederhanaan. Ini tidak dianjurkan karena risiko kesalahan ketik. Sebagai gantinya, pertimbangkan untuk menggunakan konstanta enumerasi atau string.
Dalam kode di atas, Bilah Alat bertanggung jawab untuk membuat NotificationCenter tahu jenis acara apa yang diminati, dan menerbitkan semua interaksi eksternal melalui metode notify. Kelas lain yang tertarik dengan
toolbar-button-click-event
itu hanya akan mendaftar untuk itu di konstruktornya.Variasi yang menarik pada pola ini meliputi:
Fitur menarik termasuk:
Gotcha yang menarik dan kemungkinan solusi termasuk:
sumber
buttonsToolbar
ke proyek lain yang tidak menggunakan Bus Acara?Saya dulu memperkenalkan semacam "bus acara", dan di tahun-tahun berikutnya saya mulai semakin mengandalkan Model Objek Dokumen itu sendiri untuk mengkomunikasikan acara untuk kode UI.
Di browser, DOM adalah satu-satunya ketergantungan yang selalu ada - bahkan selama pemuatan halaman. Kuncinya adalah memanfaatkan Acara Kustom dalam JavaScript, dan mengandalkan gelembung acara untuk mengomunikasikan peristiwa itu.
Sebelum orang-orang mulai berteriak tentang "menunggu dokumen siap" sebelum melampirkan pelanggan,
document.documentElement
properti mereferensikan<html>
elemen dari saat JavaScript mulai dieksekusi, tidak peduli di mana skrip diimpor atau urutan yang muncul di markup Anda.Di sinilah Anda dapat mulai mendengarkan acara.
Sangat umum untuk memiliki komponen JavaScript (atau widget) langsung di dalam tag HTML tertentu pada halaman. Elemen "root" dari komponen adalah tempat Anda dapat memicu peristiwa menggelegak Anda. Pelanggan pada
<html>
elemen akan menerima notifikasi ini sama seperti acara yang dibuat pengguna lain.Hanya beberapa contoh kode pelat ketel:
Jadi polanya menjadi:
document.documentElement
properti (tidak perlu menunggu dokumen siap)document.documentElement
.Ini harus bekerja untuk basis kode fungsional dan berorientasi objek.
sumber
Saya menggunakan gaya yang sama dengan pengembangan video game saya dengan Unity 3D. Saya membuat komponen seperti Kesehatan, Input, Statistik, Suara, dll. Dan menambahkannya ke Obyek Game untuk membangun objek objek permainan itu. Unity sudah memiliki mekanik untuk menambahkan komponen ke objek game. Namun, apa yang saya temukan adalah kebanyakan orang meminta komponen atau merujuk langsung komponen di dalam komponen lain (bahkan jika mereka menggunakan antarmuka itu masih lebih digabungkan, terima kasih saya lebih suka). Saya ingin komponen dapat dibuat dalam isolasi dengan nol dependensi komponen lainnya. Jadi saya memiliki komponen peristiwa kebakaran ketika data berubah (khusus untuk komponen) dan menyatakan metode untuk mengubah data pada dasarnya. Kemudian objek game yang saya buat kelas untuk dan menempelkan semua peristiwa komponen ke metode komponen lainnya.
Hal yang saya sukai dari ini adalah bahwa untuk melihat semua interaksi komponen untuk objek game, saya dapat melihat kelas 1 ini. Kedengarannya seperti kelas Kontak Anda sangat mirip dengan kelas Objek Game saya (saya beri nama objek game ke objek yang seharusnya seperti MainPlayer, Orc, dll).
Kelas-kelas ini adalah semacam kelas manajer. Mereka sendiri tidak benar-benar memiliki apa pun kecuali komponen dan kode untuk menghubungkan mereka. Saya tidak yakin mengapa Anda membuat metode di sini yang hanya memanggil metode komponen lain ketika Anda bisa menghubungkannya secara langsung. Maksud dari kelas ini adalah benar-benar hanya untuk mengatur acara yang terhubung.
Sebagai catatan untuk pendaftaran acara saya, saya menambahkan panggilan balik filter dan panggilan balik args. Ketika acara dipicu (saya membuat kelas acara khusus saya sendiri) itu akan memanggil panggilan balik filter jika ada dan jika kembali benar maka akan pindah ke panggilan balik args. Tujuan dari callback filter adalah untuk memberikan fleksibilitas. Suatu peristiwa dapat memicu karena berbagai alasan tetapi saya hanya ingin memanggil acara yang terhubung saya jika cek benar. Contohnya mungkin komponen Input memiliki acara OnKeyHit. Jika saya memiliki komponen Gerakan yang memiliki metode seperti MoveForward () MoveBackward (), dll. Saya dapat menghubungkan OnKeyHit + = MoveForward tapi jelas saya tidak ingin bergerak maju dengan tombol apa pun yang terkena. Saya hanya ingin melakukannya jika kuncinya adalah kunci 'w'. Karena OnKeyHit sedang mengisi argumen untuk diteruskan dan salah satunya adalah kunci yang dipukul,
Bagi saya, langganan untuk kelas pengelola objek permainan tertentu lebih mirip:
Karena komponen dapat dikembangkan secara terpisah, beberapa pemrogram dapat mengkodekannya. Dengan contoh di atas, coder input memberikan objek argumen variabel bernama Key. Namun, pengembang komponen Gerakan mungkin tidak menggunakan Kunci (jika perlu melihat argumen, dalam hal ini mungkin tidak tetapi dalam kasus lain mereka menggunakan nilai argumen yang diteruskan). Untuk menghapus persyaratan komunikasi ini, callback args bertindak sebagai pemetaan untuk argumen antar komponen. Jadi orang yang membuat game object manager class ini adalah orang yang perlu hanya tahu nama variabel arg antara 2 klien ketika mereka pergi untuk menghubungkan mereka dan melakukan pemetaan pada saat itu. Metode ini dipanggil setelah fungsi filter.
Jadi dalam situasi di atas orang Input memberi nama variabel di dalam objek args 'Key' tetapi Gerakan menamakannya 'keyPressed'. Ini membantu lebih lanjut isolasi antara komponen itu sendiri ketika mereka sedang dikembangkan dan menempatkannya pada implementer kelas manajer untuk terhubung dengan benar.
sumber
Untuk apa nilainya, saya melakukan sesuatu sebagai bagian dari proyek backend dan telah mengambil pendekatan serupa:
Bagaimana saya menangani tantangan konstruksi / perkabelan Anda:
Analogi dengan bilah alat Anda:
Masalah yang mungkin Anda hadapi:
.filter
menurut negara (sebenarnya, implementasinya lebih fungsional - percakapan adalah peta datar yang dapat diamati dari pengamatan peristiwa perubahan negara).Jadi, secara ringkas, Anda dapat melihat seluruh domain masalah Anda sebagai yang dapat diobservasi, atau 'secara fungsional' / 'secara deklaratif' dan menganggap komponen web Anda sebagai aliran peristiwa, sebagai yang dapat diamati, berasal dari bus (dapat diamati), ke mana bus (sebuah pengamat) juga berlangganan. Instansiasi yang dapat diobservasi (mis: toolbar baru) bersifat deklaratif, di mana keseluruhan proses dapat dilihat sebagai yang dapat diamati dari yang
.map
d dapat diobservasi dari aliran input.sumber