Saya tahu bahwa ketika membangun aplikasi (asli atau web) seperti yang ada di Apple AppStore atau Google Play store store, sangat umum menggunakan arsitektur Model-View-Controller.
Namun, apakah masuk akal untuk juga membuat aplikasi menggunakan arsitektur Component-Entity-System yang umum di mesin game?
design-patterns
architecture
mvc
game-development
applications
Andrew De Andrade
sumber
sumber
Jawaban:
Bagi saya, tentu saja. Saya bekerja di FX visual dan mempelajari berbagai sistem di bidang ini, arsitekturnya (termasuk CAD / CAM), haus akan SDK dan makalah apa pun yang akan memberi saya rasa pro dan kontra dari keputusan arsitektur yang tampaknya tak terbatas yang dapat dibuat, bahkan dengan yang paling halus tidak selalu membuat dampak yang halus.
VFX agak mirip dengan game di mana ada satu konsep pusat "adegan", dengan viewports yang menampilkan hasil yang diberikan. Ada juga cenderung banyak proses gila tengah berputar di sekitar adegan ini terus-menerus dalam konteks animasi, di mana mungkin ada fisika terjadi, pemancar partikel partikel pemijahan, jerat yang dianimasi dan dirender, animasi gerak, dll, dan pada akhirnya untuk membuat mereka semua ke pengguna di akhir.
Konsep lain yang mirip dengan setidaknya mesin game yang sangat kompleks adalah kebutuhan akan aspek "perancang" di mana perancang dapat secara fleksibel merancang adegan, termasuk kemampuan melakukan pemrograman ringan sendiri (skrip dan simpul).
Saya menemukan, selama bertahun-tahun, bahwa ECS paling cocok. Tentu saja itu tidak pernah benar-benar bercerai dari subjektivitas, tetapi saya akan mengatakan itu tampaknya memberikan masalah paling sedikit. Itu memecahkan lebih banyak masalah besar yang selalu kami perjuangkan, sementara hanya memberi kami beberapa masalah kecil baru sebagai balasannya.
OOP tradisional
Pendekatan OOP yang lebih tradisional bisa sangat kuat ketika Anda memiliki pemahaman yang kuat tentang persyaratan desain di muka tetapi tidak persyaratan implementasi. Baik melalui pendekatan multi antarmuka yang lebih datar atau pendekatan ABC hierarkis yang lebih bertingkat, ia cenderung memperkuat desain dan membuatnya lebih sulit untuk diubah sambil membuat implementasi lebih mudah dan lebih aman untuk diubah. Selalu ada kebutuhan untuk ketidakstabilan dalam produk apa pun yang melewati versi tunggal, sehingga pendekatan OOP cenderung condong stabilitas (kesulitan perubahan dan kurangnya alasan untuk perubahan) menuju tingkat desain, dan ketidakstabilan (kemudahan perubahan dan alasan perubahan) ke tingkat implementasi.
Namun, terhadap berkembangnya persyaratan pengguna akhir, baik desain maupun implementasi mungkin perlu sering diubah. Anda mungkin menemukan sesuatu yang aneh seperti kebutuhan pengguna akhir yang kuat untuk makhluk analogis yang perlu menjadi tanaman dan hewan sekaligus, benar-benar membatalkan seluruh model konseptual yang Anda buat. Pendekatan berorientasi objek yang normal tidak melindungi Anda di sini, dan kadang-kadang dapat membuat perubahan pemecah konsep yang tidak terduga dan lebih sulit lagi. Ketika bidang yang sangat kritis terhadap kinerja dilibatkan, alasan perubahan desain semakin bertambah banyak.
Menggabungkan banyak, antarmuka granular untuk membentuk antarmuka yang sesuai dari suatu objek dapat banyak membantu dalam menstabilkan kode klien, tetapi itu tidak membantu dalam menstabilkan subtipe yang kadang-kadang bisa mengerdilkan jumlah dependensi klien. Anda dapat memiliki satu antarmuka yang digunakan hanya oleh sebagian dari sistem Anda, misalnya, tetapi dengan ribuan subtipe yang mengimplementasikan antarmuka itu. Dalam hal itu, mempertahankan subtipe kompleks (kompleks karena mereka memiliki begitu banyak tanggung jawab antarmuka yang berbeda untuk dipenuhi) dapat menjadi mimpi buruk daripada kode yang menggunakannya melalui antarmuka. OOP cenderung untuk mentransfer kompleksitas ke tingkat objek, sementara ECS mentransfernya ke tingkat klien ("sistem"), dan itu bisa ideal ketika ada sangat sedikit sistem tetapi sejumlah besar yang sesuai dengan "objek" ("entitas").
Sebuah kelas juga memiliki datanya secara pribadi, dan dengan demikian dapat mempertahankan invarian semuanya sendiri. Namun demikian, ada invarian "kasar" yang sebenarnya masih sulit dipertahankan ketika objek berinteraksi satu sama lain. Agar sistem yang kompleks secara keseluruhan berada dalam kondisi yang valid, sering kali perlu mempertimbangkan grafik objek yang kompleks, bahkan jika invarian masing-masingnya dipertahankan dengan baik. Pendekatan gaya-OOP tradisional dapat membantu mempertahankan invarian granular, tetapi sebenarnya dapat membuat sulit untuk mempertahankan invarian luas dan kasar jika objek fokus pada aspek kecil sistem.
Di situlah pendekatan atau varian ECS lego-block-building semacam ini bisa sangat membantu. Juga dengan sistem yang lebih kasar dalam desain daripada objek biasa, menjadi lebih mudah untuk mempertahankan jenis invarian kasar pada pandangan mata burung dari sistem. Banyak interaksi objek kecil berubah menjadi satu sistem besar yang berfokus pada satu tugas besar alih-alih objek kecil mungil yang berfokus pada tugas-tugas kecil dengan grafik ketergantungan yang akan mencakup satu kilometer kertas.
Namun saya harus melihat keluar dari bidang saya, di industri game, untuk belajar tentang ECS, meskipun saya selalu salah satu dari pola pikir yang berorientasi data. Juga, cukup lucu, saya hampir membuat jalan saya menuju ECS sendiri hanya iterasi dan mencoba untuk datang dengan desain yang lebih baik. Saya tidak berhasil sampai sejauh itu dan melewatkan detail yang sangat penting, yang merupakan formalisasi dari bagian "sistem", dan meremas komponen sampai ke data mentah.
Saya akan mencoba menjelaskan bagaimana saya akhirnya memilih ECS, dan bagaimana akhirnya menyelesaikan semua masalah dengan iterasi desain sebelumnya. Saya pikir itu akan membantu menyoroti mengapa jawaban di sini bisa sangat kuat "ya", bahwa ECS berpotensi berlaku jauh melampaui industri game.
1980-an Arsitektur Brute Force
Arsitektur pertama yang saya kerjakan di industri VFX memiliki warisan panjang yang sudah melewati satu dekade sejak saya bergabung dengan perusahaan. Itu kasar kasar C coding sepanjang jalan (bukan miring pada C, karena saya suka C, tapi cara itu digunakan di sini benar-benar kasar). Irisan miniatur dan terlalu sederhana menyerupai dependensi seperti ini:
Dan ini adalah diagram yang sangat disederhanakan dari satu bagian kecil dari sistem. Setiap klien ini dalam diagram ("Rendering", "Fisika", "Motion") akan mendapatkan beberapa objek "generik" di mana mereka akan memeriksa bidang jenis, seperti:
Tentu saja dengan kode yang jauh lebih jelek dan lebih kompleks dari ini. Seringkali fungsi-fungsi tambahan akan dipanggil dari sakelar-sakelar sakelar ini yang secara rekursif akan melakukan sakelar berulang-ulang. Diagram dan kode ini mungkin hampir terlihat seperti ECS-lite, tetapi tidak ada perbedaan entitas-komponen yang kuat (" apakah objek ini kamera?", Bukan "apakah objek ini memberikan gerakan?"), Dan tidak ada formalisasi "sistem" ( hanya sekelompok fungsi bersarang di semua tempat dan menggabungkan tanggung jawab). Dalam hal itu, hampir semuanya rumit, fungsi apa pun merupakan potensi bencana yang menunggu untuk terjadi.
Prosedur pengujian kami di sini sering harus memeriksa hal-hal seperti jerat yang terpisah dari jenis barang lainnya, bahkan jika hal yang sama terjadi pada keduanya, karena sifat kasar dari pengkodean di sini (sering disertai dengan banyak salinan dan tempel) sering dilakukan sangat mungkin bahwa apa yang sebaliknya logika yang sama bisa gagal dari satu jenis item ke yang berikutnya. Mencoba memperluas sistem untuk menangani jenis barang baru itu cukup sia-sia, meskipun ada kebutuhan pengguna akhir yang sangat kuat, karena terlalu sulit ketika kami berjuang sangat keras hanya untuk menangani jenis barang yang ada.
Beberapa pro:
Beberapa kontra:
Arsitektur COM 1990-an
Sebagian besar industri VFX menggunakan gaya arsitektur ini dari apa yang telah saya kumpulkan, membaca dokumen tentang keputusan desain mereka dan melirik kit pengembangan perangkat lunak mereka.
Ini mungkin bukan COM pada level ABI (beberapa arsitektur ini hanya bisa memiliki plugin yang ditulis menggunakan kompiler yang sama), tetapi berbagi banyak karakteristik serupa dengan kueri antarmuka yang dibuat pada objek untuk melihat antarmuka apa yang didukung komponen mereka.
Dengan pendekatan semacam ini,
transform
fungsi analogis di atas menyerupai bentuk ini:Ini adalah pendekatan tim baru dari basis kode lama yang menetap, untuk akhirnya refactor ke arah. Dan itu adalah peningkatan dramatis dibandingkan yang asli dalam hal fleksibilitas dan pemeliharaan, tetapi masih ada beberapa masalah yang akan saya bahas di bagian selanjutnya.
Beberapa pro:
Beberapa kontra:
IMotion
akan selalu memiliki status yang sama persis dan implementasi yang sama persis untuk semua fungsi. Untuk mengurangi ini, kami akan mulai memusatkan kelas-kelas dasar dan fungsionalitas pembantu di seluruh sistem untuk hal-hal yang cenderung diterapkan secara berlebihan dengan cara yang sama untuk antarmuka yang sama, dan mungkin dengan beberapa pewarisan yang terjadi di belakang tenda, tapi itu cukup berantakan di bawah tenda meskipun kode klien mudah.QueryInterface
fungsi dasar yang hampir selalu muncul sebagai hotspot menengah ke atas, dan kadang-kadang bahkan hotspot # 1. Untuk mengurangi itu, kami akan melakukan hal-hal seperti memiliki merender bagian dari basis kode cache daftar objek yang sudah dikenal untuk mendukungIRenderable
, tapi itu secara signifikan meningkatkan kompleksitas dan biaya perawatan. Demikian juga, ini lebih sulit untuk diukur tetapi kami melihat beberapa perlambatan yang pasti dibandingkan dengan pengkodean C-style yang kami lakukan sebelumnya ketika setiap antarmuka tunggal memerlukan pengiriman dinamis. Hal-hal seperti mispredictions cabang dan hambatan optimisasi sulit diukur di luar aspek kode yang sedikit, tetapi para pengguna umumnya memperhatikan responsif dari antarmuka pengguna dan hal-hal seperti itu semakin buruk dengan membandingkan versi sebelumnya dan yang lebih baru dari perangkat lunak secara berdampingan. sisi untuk area di mana kompleksitas algoritmik tidak berubah, hanya konstanta.Respon Pragmatis: Komposisi
Salah satu hal yang kami perhatikan sebelumnya (atau setidaknya saya adalah) yang menyebabkan masalah adalah yang
IMotion
mungkin diimplementasikan oleh 100 kelas yang berbeda tetapi dengan implementasi yang sama persis dan negara terkait. Selain itu, itu hanya akan digunakan oleh beberapa sistem seperti rendering, gerakan keyframed, dan fisika.Jadi dalam kasus seperti itu, kita mungkin memiliki hubungan 3-ke-1 antara sistem yang menggunakan antarmuka ke antarmuka, dan hubungan 100-ke-1 antara subtipe yang mengimplementasikan antarmuka ke antarmuka.
Kompleksitas dan pemeliharaan kemudian akan secara drastis condong ke implementasi dan pemeliharaan 100 subtipe, bukan 3 sistem klien yang bergantung
IMotion
. Ini menggeser semua kesulitan perawatan kami ke pemeliharaan 100 subtipe ini, bukan 3 tempat yang menggunakan antarmuka. Memperbarui 3 tempat dalam kode dengan sedikit atau tidak ada "kopling eferen tidak langsung" (seperti dalam ketergantungannya tetapi secara tidak langsung melalui antarmuka, bukan ketergantungan langsung), bukan masalah besar: memperbarui 100 tempat subtipe dengan muatan kapal "kopling eferen tidak langsung" , masalah besar *.Jadi saya harus berusaha keras tetapi saya mengusulkan agar kami mencoba menjadi sedikit lebih pragmatis dan mengendurkan seluruh ide "antarmuka murni". Tidak masuk akal bagi saya untuk membuat sesuatu yang
IMotion
sepenuhnya abstrak dan tanpa kewarganegaraan kecuali kita melihat manfaatnya memiliki beragam implementasi. Dalam kasus kami,IMotion
memiliki beragam implementasi yang kaya akan benar-benar berubah menjadi mimpi buruk pemeliharaan, karena kami tidak menginginkan variasi. Alih-alih, kami melakukan iterasi untuk mencoba membuat implementasi gerakan tunggal yang benar-benar bagus terhadap perubahan kebutuhan klien, dan sering kali bekerja di sekitar ide antarmuka murni yang banyak mencoba memaksa setiap implementorIMotion
untuk menggunakan implementasi yang sama dan status yang terkait sehingga kami tidak t tujuan rangkap.Antarmuka menjadi lebih luas
Behaviors
terkait dengan entitas.IMotion
hanya akan menjadiMotion
"komponen" (saya mengubah cara kami mendefinisikan "komponen" dari COM ke yang lebih dekat dengan definisi biasa, dari bagian yang membentuk entitas "lengkap").Alih-alih ini:
Kami mengembangkannya menjadi sesuatu yang lebih seperti ini:
Ini adalah pelanggaran terang-terangan dari prinsip inversi ketergantungan untuk mulai bergeser dari abstrak kembali ke beton, tetapi bagi saya tingkat abstraksi seperti itu hanya berguna jika kita dapat meramalkan kebutuhan asli di masa depan, di luar keraguan yang masuk akal dan tidak menggunakan skenario "bagaimana jika" yang konyol sepenuhnya terlepas dari pengalaman pengguna (yang mungkin akan memerlukan perubahan desain), untuk fleksibilitas seperti itu.
Jadi kami mulai berevolusi ke desain ini.
QueryInterface
menjadi lebih sepertiQueryBehavior
. Lebih jauh lagi, mulai tampak tidak ada gunanya menggunakan warisan di sini. Kami menggunakan komposisi sebagai gantinya. Objek berubah menjadi kumpulan komponen yang ketersediaannya dapat ditanyakan dan disuntikkan pada saat runtime.Beberapa pro:
Motion
implementasi yang sangat sentral dan jelas , misalnya, dan tidak tersebar di seratus subtipe.Beberapa kontra:
Salah satu fenomena yang terjadi adalah, karena kami kehilangan abstraksi pada komponen perilaku ini, kami memiliki lebih dari itu. Misalnya, alih-alih
IRenderable
komponen abstrak , kami akan melampirkan objek dengan betonMesh
atauPointSprites
komponen. Sistem rendering akan tahu cara membuatMesh
danPointSprites
komponen dan akan menemukan entitas yang menyediakan komponen tersebut dan menggambar itu. Di lain waktu, kami memiliki renderables lain-lain sepertiSceneLabel
yang kami temukan kami butuhkan di belakang, dan jadi kami akan melampirkanSceneLabel
dalam kasus-kasus tersebut ke entitas yang relevan (mungkin selain aMesh
). Implementasi sistem rendering kemudian akan diperbarui untuk mengetahui cara membuat entitas yang menyediakannya, dan itu adalah perubahan yang cukup mudah dibuat.Dalam hal ini, entitas yang terdiri dari komponen juga dapat digunakan sebagai komponen untuk entitas lain. Kami akan membangun hal-hal seperti itu dengan memasang blok lego.
ECS: Sistem dan Komponen Data Mentah
Sistem terakhir sejauh yang saya buat sendiri, dan kami masih membastardisasi dengan COM. Rasanya seperti ingin menjadi sistem entitas-entitas, tetapi saya tidak terbiasa dengannya saat itu. Saya melihat-lihat contoh gaya COM yang memenuhi bidang saya, ketika saya seharusnya mencari mesin game AAA untuk inspirasi arsitektur. Saya akhirnya mulai melakukan itu.
Apa yang saya lewatkan adalah beberapa ide kunci:
Saya akhirnya meninggalkan perusahaan itu dan mulai mengerjakan ECS sebagai indy (masih mengerjakannya sambil menguras tabungan saya), dan itu merupakan sistem yang paling mudah untuk dikelola sejauh ini.
Apa yang saya perhatikan dengan pendekatan ECS adalah bahwa itu menyelesaikan masalah yang masih saya perjuangkan di atas. Yang paling penting bagi saya, rasanya seperti kami mengelola "kota-kota" berukuran sehat dan bukannya desa kecil dengan interaksi yang kompleks. Itu tidak sulit untuk dipertahankan sebagai "megalopolis" monolitik, terlalu besar dalam populasi untuk dikelola secara efektif, tetapi tidak semrawut seperti dunia yang dipenuhi dengan desa-desa kecil yang berinteraksi satu sama lain di mana hanya memikirkan rute perdagangan di di antara mereka membentuk grafik mimpi buruk. ECS menyaring semua kompleksitas menuju "sistem" besar, seperti sistem render, "kota" berukuran sehat tetapi bukan "megalopolis yang terlalu padat".
Komponen yang menjadi data mentah terasa sangat aneh bagi saya pada awalnya, karena bahkan merusak prinsip dasar penyembunyian informasi OOP. Itu agak menantang salah satu nilai terbesar yang saya sayangi tentang OOP, yang merupakan kemampuannya untuk mempertahankan invarian yang membutuhkan enkapsulasi dan penyembunyian informasi. Tapi itu mulai menjadi bukan masalah karena dengan cepat menjadi jelas apa yang terjadi dengan hanya selusin sistem yang luas mengubah data itu bukannya logika seperti itu tersebar di ratusan hingga ribuan subtipe yang menerapkan kombinasi antarmuka. Saya cenderung menganggapnya seperti masih dalam gaya OOP kecuali menyebar di mana sistem menyediakan fungsionalitas dan implementasi yang mengakses data, komponen menyediakan data, dan entitas menyediakan komponen.
Menjadi lebih mudah , kontra-intuitif, untuk memikirkan tentang efek samping yang disebabkan oleh sistem ketika hanya ada beberapa sistem besar mengubah data dalam melewati lebar. Sistem menjadi lebih "rata", tumpukan panggilan saya menjadi lebih dangkal dari sebelumnya untuk setiap utas. Saya bisa memikirkan sistem di tingkat pengawas itu dan tidak mengalami kejutan aneh.
Demikian juga, hal itu membuat area yang sangat kritis terhadap kinerja menjadi sederhana sehubungan dengan penghapusan pertanyaan itu. Karena gagasan "Sistem" menjadi sangat formal, sistem dapat berlangganan komponen yang diminati, dan hanya menyerahkan daftar entitas yang di-cache yang memenuhi kriteria tersebut. Setiap individu tidak perlu mengelola optimasi caching itu, ia menjadi terpusat ke satu tempat.
Beberapa pro:
Beberapa kontra:
Jadi, saya akan mengatakan "ya", dengan contoh VFX pribadi saya menjadi kandidat yang kuat. Tapi itu masih cukup mirip dengan kebutuhan gaming.
Saya belum mempraktikkannya di daerah terpencil yang sepenuhnya terlepas dari kekhawatiran mesin game (VFX sangat mirip), tetapi bagi saya sepertinya lebih banyak area yang merupakan kandidat yang baik untuk pendekatan ECS. Mungkin bahkan sistem GUI akan cocok untuk satu, tapi saya masih menggunakan pendekatan OOP lebih di sana (tetapi tanpa warisan yang mendalam tidak seperti Qt, misalnya).
Ini adalah wilayah yang belum dijelajahi secara luas, tetapi tampaknya cocok untuk saya setiap kali entitas Anda dapat terdiri dari kombinasi "sifat" yang kaya (dan kombinasi karakter apa yang mereka dapat berubah), dan di mana Anda memiliki beberapa generalisasi sistem yang memproses entitas yang memiliki sifat yang diperlukan.
Dalam kasus-kasus itu menjadi alternatif yang sangat praktis untuk skenario apa pun di mana Anda mungkin tergoda untuk menggunakan sesuatu seperti pewarisan berganda atau emulasi konsep (mixin, misalnya) hanya untuk menghasilkan ratusan atau lebih kombo dalam hierarki warisan yang dalam atau ratusan kombo. kelas dalam hierarki datar yang mengimplementasikan kombo antarmuka tertentu, tetapi di mana sistem Anda sedikit jumlahnya (puluhan, misalnya).
Dalam kasus tersebut, kompleksitas basis kode mulai terasa lebih proporsional dengan jumlah sistem daripada jumlah kombinasi jenis, karena masing-masing jenis sekarang hanya entitas yang menyusun komponen yang tidak lebih dari data mentah. Sistem GUI secara alami cocok dengan jenis spesifikasi ini di mana mereka mungkin memiliki ratusan jenis widget yang mungkin digabungkan dari jenis dasar atau antarmuka lainnya, tetapi hanya beberapa sistem untuk memprosesnya (sistem tata letak, sistem render, dll.). Jika sistem GUI menggunakan ECS, mungkin akan jauh lebih mudah untuk alasan tentang kebenaran sistem ketika semua fungsionalitas disediakan oleh segelintir sistem ini daripada ratusan jenis objek yang berbeda dengan antarmuka yang diwariskan atau kelas dasar. Jika sistem GUI menggunakan ECS, widget tidak akan memiliki fungsionalitas, hanya data. Hanya segelintir sistem yang memproses entitas widget yang memiliki fungsionalitas. Bagaimana peristiwa yang bisa ditimpa widget akan ditangani di luar saya, tetapi hanya berdasarkan pengalaman saya yang terbatas sejauh ini, saya belum menemukan kasus di mana jenis logika tidak dapat ditransfer secara terpusat ke sistem yang diberikan dengan cara yang, dalam Tinjau kembali, menghasilkan solusi yang jauh lebih elegan yang pernah saya harapkan.
Saya ingin melihatnya bekerja di lebih banyak bidang, karena itu adalah penyelamat di tambang. Tentu saja itu tidak cocok jika desain Anda tidak rusak dengan cara ini, dari entitas yang mengumpulkan komponen ke sistem kasar yang memproses komponen-komponen itu, tetapi jika mereka secara alami sesuai dengan model semacam ini, itu adalah hal paling indah yang pernah saya temui. .
sumber
Arsitektur Component-Entity-System untuk mesin game berfungsi untuk game karena sifat perangkat lunak game, dan karakteristik unik serta persyaratan kualitasnya. Sebagai contoh, entitas menyediakan cara seragam untuk menangani dan bekerja dengan hal-hal dalam permainan, yang mungkin berbeda secara drastis dalam tujuan dan penggunaannya, tetapi perlu dirender, diperbarui, atau diserialisasi / diserialisasi oleh sistem dengan cara yang seragam. Dengan memasukkan model komponen ke dalam arsitektur ini, Anda memungkinkan mereka untuk menjaga struktur inti yang sederhana, sambil menambahkan lebih banyak fitur dan fungsi sesuai kebutuhan, dengan kopling kode rendah. Ada sejumlah sistem perangkat lunak yang berbeda yang dapat mengambil manfaat dari karakteristik desain ini, seperti aplikasi CAD, codec A / V,
TL; DR - Pola desain hanya berfungsi dengan baik ketika domain masalah cukup sesuai dengan fitur dan kelemahan yang mereka timbulkan pada desain.
sumber
Jika domain masalah cocok untuk itu, tentu saja.
Pekerjaan saya saat ini melibatkan aplikasi yang perlu mendukung berbagai kemampuan tergantung pada banyak faktor runtime. Menggunakan entitas berbasis komponen untuk memisahkan semua kemampuan itu dan memungkinkan ekstensibilitas dan testabilitas dalam isolasi sangat ideal bagi kami.
sunting: Pekerjaan saya melibatkan penyediaan konektivitas ke perangkat keras berpemilik (dalam C #). Bergantung pada faktor-bentuk perangkat kerasnya, firmware apa yang dipasang di sana, tingkat layanan apa yang telah dibeli oleh klien, dll., Dll. Kita perlu menyediakan tingkat fungsionalitas yang berbeda untuk perangkat. Bahkan beberapa fitur yang memiliki antarmuka yang sama memiliki implementasi yang berbeda tergantung pada versi perangkatnya.
Basis kode sebelumnya di sini memiliki antarmuka yang sangat luas dan banyak yang tidak diimplementasikan. Beberapa memiliki banyak antarmuka tipis yang kemudian disusun secara statis dalam satu kelas beasty. Beberapa hanya menggunakan string -> kamus string untuk memodelkannya. (kami memiliki banyak departemen yang semuanya berpikir mereka dapat melakukannya dengan lebih baik)
Ini semua memiliki kekurangan. Antarmuka yang lebar adalah rasa sakit setengah untuk mengejek / menguji secara efektif. Menambahkan fitur baru berarti mengubah antarmuka publik (dan semua implementasi yang ada). Banyak antarmuka yang tipis menyebabkan kode yang dikonsumsi sangat jelek, tetapi karena kami akhirnya melewati pengujian objek besar lemak masih menderita. Plus antarmuka yang tipis tidak mengelola dependensi mereka dengan baik. Kamus string memiliki masalah penguraian dan eksistensi yang biasa dan juga lubang neraka kinerja, keterbacaan, dan pemeliharaan.
Apa yang kami gunakan sekarang adalah entitas yang sangat ramping yang komponennya ditemukan dan disusun berdasarkan info runtime. Dependensi dilakukan secara deklaratif dan diselesaikan secara otomatis oleh kerangka kerja komponen inti. Komponen itu sendiri dapat diuji secara terpisah karena mereka bekerja secara langsung dengan dependensinya, dan masalah dengan dependensi yang hilang ditemukan lebih awal - dan di satu lokasi daripada penggunaan pertama dependensi. Komponen baru (atau pengujian) dapat dimasukkan dan tidak ada kode yang terpengaruh olehnya. Konsumen meminta entitas untuk antarmuka ke komponen, jadi kami bebas untuk bermain-main dengan berbagai implementasi (dan bagaimana implementasi dipetakan ke data runtime) dengan kebebasan relatif.
Untuk situasi seperti ini di mana komposisi objek dan interface-nya dapat mencakup beberapa (sangat bervariasi) komponen umum, ia bekerja dengan sangat baik.
sumber