Dalam konteks posting ini oleh Igor Minar, pimpinan AngularJS:
MVC vs MVVM vs MVP . Apa topik yang kontroversial bahwa banyak pengembang dapat menghabiskan berjam-jam berdebat dan berdebat tentang
Selama beberapa tahun AngularJS lebih dekat dengan MVC (atau lebih tepatnya salah satu varian sisi kliennya), tetapi seiring berjalannya waktu dan berkat banyak refactoring dan peningkatan api, sekarang lebih dekat ke MVVM - objek $ scope dapat dianggap sebagai ViewModel yang sedang dikembangkan. dihiasi oleh fungsi yang kita sebut Pengendali .
Mampu mengategorikan kerangka kerja dan memasukkannya ke dalam salah satu ember MV * memiliki beberapa keunggulan. Ini dapat membantu pengembang lebih nyaman dengan apisnya dengan membuatnya lebih mudah untuk membuat model mental yang mewakili aplikasi yang sedang dibangun dengan kerangka kerja. Ini juga dapat membantu membangun terminologi yang digunakan oleh pengembang.
Karena itu, saya lebih suka melihat pengembang membangun aplikasi kick-ass yang dirancang dengan baik dan mengikuti pemisahan kekhawatiran, daripada melihat mereka membuang-buang waktu berdebat tentang MV * omong kosong. Dan untuk alasan ini, saya menyatakan AngularJS sebagai kerangka kerja MVW - Model-View-Apapun . Di mana Apapun singkatan " apa pun yang bekerja untuk Anda ".
Angular memberi Anda banyak fleksibilitas untuk memisahkan logika presentasi dari logika bisnis dan status presentasi. Silakan gunakan bahan bakar produktivitas dan pemeliharaan aplikasi Anda daripada diskusi panas tentang hal-hal yang pada akhirnya tidak terlalu penting.
Apakah ada rekomendasi atau pedoman untuk menerapkan pola desain AngularJS MVW (Model-View-Apapun) dalam aplikasi sisi klien?
sumber
Jawaban:
Berkat sejumlah besar sumber berharga saya punya beberapa rekomendasi umum untuk menerapkan komponen dalam aplikasi AngularJS:
Pengendali
Kontroler harus hanya merupakan interaksi antara model dan tampilan. Cobalah membuatnya setipis mungkin.
Sangat disarankan untuk menghindari logika bisnis dalam pengontrol. Itu harus dipindahkan ke model.
Pengontrol dapat berkomunikasi dengan pengontrol lain menggunakan doa metode (mungkin ketika anak-anak ingin berkomunikasi dengan orang tua) atau $ emit , $ broadcast dan $ on metode. Pesan yang dipancarkan dan disiarkan harus dijaga agar tetap minimum.
Pengontrol seharusnya tidak peduli dengan presentasi atau manipulasi DOM.
Cobalah untuk menghindari pengendali bersarang . Dalam hal ini pengendali orangtua diartikan sebagai model. Suntikkan model sebagai layanan bersama.
Lingkup pada pengontrol harus digunakan untuk model penjilidan dengan tampilan dan
enkapsulasi Model Tampilan sebagaimana untuk pola desain Model Presentasi .
Cakupan
Perlakukan ruang lingkup sebagai read-only dalam templat dan write-only di controller . Tujuan dari ruang lingkup adalah untuk merujuk pada model, bukan untuk menjadi model.
Saat melakukan pengikatan dua arah (model-ng) pastikan Anda tidak mengikat langsung ke properti scope.
Model
Model dalam AngularJS adalah singleton yang ditentukan oleh layanan .
Model menyediakan cara terbaik untuk memisahkan data dan tampilan.
Model adalah kandidat utama untuk pengujian unit, karena mereka biasanya memiliki tepat satu dependensi (beberapa bentuk emitor acara, biasanya $ rootScope ) dan berisi logika domain yang sangat dapat diuji .
Model harus dipertimbangkan sebagai implementasi dari unit tertentu. Ini didasarkan pada prinsip tanggung jawab tunggal. Unit adalah contoh yang bertanggung jawab atas ruang lingkup logika terkait yang dapat mewakili entitas tunggal di dunia nyata dan menggambarkannya dalam dunia pemrograman dalam hal data dan status .
Model harus merangkum data aplikasi Anda dan menyediakan API untuk mengakses dan memanipulasi data itu.
Model harus portabel sehingga dapat dengan mudah diangkut ke aplikasi serupa.
Dengan mengisolasi unit logic dalam model Anda, Anda telah membuatnya lebih mudah untuk menemukan, memperbarui, dan memelihara.
Model dapat menggunakan metode model global yang lebih umum yang umum untuk seluruh aplikasi.
Cobalah untuk menghindari komposisi model lain ke dalam model Anda menggunakan injeksi ketergantungan jika tidak benar-benar tergantung untuk mengurangi kopling komponen dan meningkatkan unit testability dan usability .
Cobalah untuk menghindari menggunakan pendengar acara dalam model. Itu membuat mereka lebih sulit untuk menguji dan umumnya membunuh model dalam hal prinsip tanggung jawab tunggal.
Implementasi Model
Karena model harus merangkum beberapa logika dalam hal data dan keadaan, itu harus secara arsitektural membatasi akses ke para anggotanya sehingga kami dapat menjamin kopling longgar.
Cara untuk melakukannya dalam aplikasi AngularJS adalah dengan mendefinisikannya menggunakan jenis layanan pabrik . Ini akan memungkinkan kami untuk mendefinisikan properti dan metode pribadi dengan sangat mudah dan juga mengembalikan yang dapat diakses secara publik di satu tempat yang akan membuatnya benar-benar dapat dibaca oleh pengembang.
Contoh :
Membuat instance baru
Cobalah untuk menghindari memiliki pabrik yang mengembalikan fungsi baru karena ini mulai memecah injeksi ketergantungan dan perpustakaan akan berperilaku canggung, terutama untuk pihak ketiga.
Cara yang lebih baik untuk mencapai hal yang sama adalah dengan menggunakan pabrik sebagai API untuk mengembalikan koleksi objek dengan metode pengambil dan penyetel yang melekat padanya.
Model Global
Secara umum cobalah untuk menghindari situasi seperti itu dan desain model Anda dengan benar sehingga dapat disuntikkan ke pengontrol dan digunakan dalam pandangan Anda.
Dalam kasus tertentu beberapa metode memerlukan aksesibilitas global dalam aplikasi. Untuk memungkinkannya, Anda dapat mendefinisikan properti ' umum ' di $ rootScope dan mengikatnya ke commonModel selama aplikasi bootstrap:
Semua metode global Anda akan hidup dalam properti ' umum '. Ini adalah semacam namespace .
Tetapi jangan mendefinisikan metode apa pun secara langsung di $ rootScope Anda . Hal ini dapat menyebabkan perilaku yang tidak terduga saat digunakan dengan arahan ngModel dalam lingkup tampilan Anda, umumnya membuang sampah di ruang lingkup Anda dan mengarah ke metode lingkup mengatasi masalah.
Sumber
Sumber daya memungkinkan Anda berinteraksi dengan berbagai sumber data .
Harus diimplementasikan menggunakan prinsip tanggung jawab tunggal .
Dalam kasus tertentu, ini adalah proxy yang dapat digunakan kembali ke titik akhir HTTP / JSON.
Sumber daya disuntikkan dalam model dan memberikan kemungkinan untuk mengirim / mengambil data.
Implementasi sumber daya
Pabrik yang membuat objek sumber daya yang memungkinkan Anda berinteraksi dengan sumber data sisi server RESTful.
Objek sumber daya yang dikembalikan memiliki metode tindakan yang menyediakan perilaku tingkat tinggi tanpa perlu berinteraksi dengan layanan $ http tingkat rendah.
Jasa
Baik model maupun sumber daya adalah layanan .
Layanan tidak terkait, unit fungsionalitas yang digabungkan secara mandiri yang mandiri.
Layanan adalah fitur yang dibawa Angular ke aplikasi web sisi klien dari sisi server, di mana layanan telah umum digunakan untuk waktu yang lama.
Layanan di aplikasi Angular adalah objek yang dapat diganti yang disatukan menggunakan injeksi ketergantungan.
Angular hadir dengan berbagai jenis layanan. Masing-masing dengan kasus penggunaannya sendiri. Silakan baca Memahami Jenis Layanan untuk detailnya.
Cobalah untuk mempertimbangkan prinsip-prinsip utama arsitektur layanan dalam aplikasi Anda.
Secara umum menurut Glosarium Layanan Web :
Struktur sisi klien
Secara umum sisi klien dari aplikasi ini dibagi menjadi beberapa modul . Setiap modul harus dapat diuji sebagai satu unit.
Cobalah untuk mendefinisikan modul tergantung pada fitur / fungsi atau tampilan , bukan berdasarkan jenis. Lihat presentasi Misko untuk detailnya.
Komponen modul dapat dikelompokkan secara konvensional berdasarkan jenis seperti pengontrol, model, tampilan, filter, arahan, dll.
Tetapi modul itu sendiri tetap dapat digunakan kembali , dapat ditransfer dan diuji .
Juga jauh lebih mudah bagi pengembang untuk menemukan beberapa bagian kode dan semua dependensinya.
Lihat Organisasi Kode di AngularJS Besar dan Aplikasi JavaScript untuk detailnya.
Contoh penataan folder :
Contoh yang bagus dari penataan aplikasi sudut diterapkan oleh aplikasi angular - https://github.com/angular-app/angular-app/tree/master/client/src
Ini juga dipertimbangkan oleh generator aplikasi modern - https://github.com/yeoman/generator-angular/issues/109
sumber
searchModel
tidak mengikuti saran penggunaan kembali. Akan lebih baik mengimpor konstanta melaluiconstant
layanan. 3. Ada penjelasan apa yang dimaksud di sini ?:Try to avoid having a factory that returns a new able function
prototype
properti objek merusak warisan, sebagai gantinya orang dapat menggunakanCar.prototype.save = ...
object
ekspresi mengikat dua arah untuk memastikan Anda menulis ke properti atausetter
fungsi yang tepat . Jika menggunakan properti langsung lingkup Anda ( tanpa titik ), Anda berisiko menyembunyikan properti target yang diinginkan dengan properti yang baru dibuat di ruang lingkup terdekat terdekat dalam rantai prototipe saat menulisnya. Ini lebih baik dijelaskan dalam presentasi MiskoSaya percaya pendapat Igor tentang hal ini, seperti terlihat dalam kutipan yang Anda berikan, hanyalah puncak gunung es dari masalah yang jauh lebih besar.
MVC dan turunannya (MVP, PM, MVVM) semuanya bagus dan bagus dalam satu agen, tetapi arsitektur server-klien adalah untuk semua tujuan sistem dua agen, dan orang-orang sering begitu terobsesi dengan pola-pola ini sehingga mereka lupa bahwa masalah yang ada jauh lebih kompleks. Dengan berusaha mematuhi prinsip-prinsip ini, mereka benar-benar berakhir dengan arsitektur yang cacat.
Mari kita lakukan ini sedikit demi sedikit.
Pedoman
Tampilan
Dalam konteks Angular, tampilan adalah DOM. Pedomannya adalah:
Melakukan:
Jangan:
Seperti menggoda, pendek, dan tidak berbahaya ini terlihat:
Ini cukup banyak menandakan setiap pengembang yang sekarang mengerti bagaimana sistem bekerja mereka perlu memeriksa kedua file Javascript, dan yang HTML.
Pengontrol
Melakukan:
Jangan:
Alasan untuk pedoman terakhir adalah bahwa pengontrol adalah saudara untuk dilihat, bukan entitas; mereka juga tidak dapat digunakan kembali.
Anda bisa berargumen bahwa arahan dapat digunakan kembali, tetapi arahan juga adalah saudara untuk dilihat (DOM) - mereka tidak pernah dimaksudkan untuk berhubungan dengan entitas.
Tentu, kadang-kadang pandangan mewakili entitas, tapi itu kasus yang agak spesifik.
Dengan kata lain, pengontrol akan fokus pada presentasi - jika Anda memasukkan logika bisnis, tidak hanya Anda akan berakhir dengan pengontrol yang sedikit meningkat dan tidak terkendali, tetapi Anda juga melanggar prinsip pemisahan perhatian .
Dengan demikian, pengontrol di Angular benar-benar lebih dari Model Presentasi atau MVVM .
Jadi, jika pengendali tidak boleh berurusan dengan logika bisnis, siapa yang harus?
Apa itu model?
Model klien Anda seringkali parsial dan basi
Kecuali Anda menulis aplikasi web offline, atau aplikasi yang sangat sederhana (beberapa entitas), model klien Anda kemungkinan besar adalah:
Model nyata harus bertahan
Dalam MCV tradisional, model adalah satu-satunya yang bertahan . Setiap kali kita berbicara tentang model, ini harus tetap ada di beberapa titik. Klien Anda dapat memanipulasi model sesuka hati, tetapi sampai perjalanan pulang-pergi ke server selesai dengan sukses, pekerjaan itu belum selesai.
Konsekuensi
Dua poin di atas harus berfungsi sebagai peringatan - model yang dipegang klien Anda hanya dapat melibatkan sebagian, sebagian besar logika bisnis sederhana.
Karena itu, mungkin bijaksana, dalam konteks klien, untuk menggunakan huruf kecil
M
- jadi itu benar-benar mVC , mVP , dan mVVm . Yang besarM
untuk server.Logika bisnis
Mungkin salah satu konsep paling penting tentang model bisnis adalah bahwa Anda dapat membaginya menjadi 2 jenis (Saya menghilangkan pandangan bisnis- ketiga karena itu adalah cerita untuk hari lain):
firstName
dansirName
properti, seperti rajin giat yanggetFullName()
dapat dianggap independen aplikasi.Penting untuk ditekankan bahwa kedua hal ini dalam konteks klien bukan logika bisnis 'nyata' - mereka hanya berurusan dengan bagian yang penting bagi klien. Logika aplikasi (bukan logika domain) harus memiliki tanggung jawab memfasilitasi komunikasi dengan server dan sebagian besar interaksi pengguna; sementara logika domain sebagian besar berskala kecil, spesifik entitas, dan berbasis presentasi.
Pertanyaannya masih tetap - di mana Anda melemparkan mereka dalam aplikasi sudut?
Arsitektur 3 vs 4 layer
Semua kerangka kerja MVW ini menggunakan 3 lapisan:
Tetapi ada dua masalah mendasar dengan ini ketika datang ke klien:
Alternatif strategi ini adalah strategi 4 layer :
Kesepakatan sebenarnya di sini adalah lapisan aturan bisnis aplikasi (Use cases), yang seringkali tidak beres pada klien.
Lapisan ini diwujudkan oleh interaksor (Paman Bob), yang cukup banyak apa yang Martin Fowler sebut lapisan layanan skrip operasi .
Contoh nyata
Pertimbangkan aplikasi web berikut:
Beberapa hal harus terjadi sekarang:
Di mana kita membuang semua ini?
Jika arsitektur Anda melibatkan pengontrol yang memanggil
$resource
, semua ini akan terjadi di dalam pengontrol. Tetapi ada strategi yang lebih baik.Solusi yang diusulkan
Diagram berikut menunjukkan bagaimana masalah di atas dapat diselesaikan dengan menambahkan lapisan logika aplikasi lain di klien Angular:
Jadi kami menambahkan lapisan antara pengontrol ke $ resource, lapisan ini (mari kita sebut itu interaktor ):
UserInteractor
.Maka, dengan persyaratan contoh konkret di atas:
validate()
validate()
metode model .createUser()
sumber
Masalah kecil dibandingkan dengan saran hebat dalam jawaban Artem, tetapi dalam hal keterbacaan kode, saya menemukan yang terbaik untuk mendefinisikan API sepenuhnya di dalam
return
objek, untuk meminimalkan bolak-balik dalam kode untuk melihat variabel mana saja didefinisikan:Jika
return
objek menjadi terlihat "terlalu ramai", itu adalah pertanda bahwa Layanan melakukan terlalu banyak.sumber
AngularJS tidak mengimplementasikan MVC dengan cara tradisional, melainkan mengimplementasikan sesuatu yang lebih dekat ke MVVM (Model-View-ViewModel), ViewModel juga dapat disebut sebagai pengikat (dalam kasus sudut dapat $ lingkup). Model -> Seperti yang kita ketahui model dalam angular dapat berupa objek JS biasa saja atau data dalam aplikasi kita
Tampilan -> tampilan dalam angularJS adalah HTML yang telah diuraikan dan dikompilasi oleh angularJS dengan menerapkan arahan atau instruksi atau binding, Titik utama di sini adalah di sudut input bukan hanya string HTML biasa (innerHTML), melainkan adalah DOM dibuat oleh browser.
The ViewModel -> ViewModel sebenarnya adalah pengikat / jembatan antara tampilan Anda dan model dalam kasus angularJS itu adalah $ scope, untuk menginisialisasi dan menambah $ scope yang kita gunakan Controller.
Jika saya ingin meringkas jawabannya: Dalam aplikasi angularJS $ scope memiliki referensi ke data, Controller mengontrol perilaku, dan View menangani tata letak dengan berinteraksi dengan controller untuk berperilaku sesuai.
sumber
Agar lebih jernih tentang pertanyaan, Angular menggunakan pola desain yang berbeda yang sudah kami temui dalam pemrograman reguler kami. 1) Ketika kami mendaftarkan pengontrol atau arahan, pabrik, layanan dll terkait modul kami. Ini dia menyembunyikan data dari ruang global. Yang merupakan pola modul . 2) Ketika sudut menggunakan pemeriksaan kotor untuk membandingkan variabel ruang lingkup, di sini ia menggunakan Pola Pengamat . 3) Semua cakupan anak induk di pengontrol kami menggunakan pola Prototypal. 4) Dalam hal menyuntikkan layanan menggunakan Pola Pabrik .
Secara keseluruhan ia menggunakan pola desain yang dikenal berbeda untuk memecahkan masalah.
sumber