Hai,
Terima kasih telah menulis artikel ini di CQRS. Saya mencoba untuk memahami bagaimana implementasinya terlihat dan saya melihat contohnya. Kode repositori sampel yang diberikan dalam contoh terlihat sangat mirip dengan cara biasanya seseorang akan menulis repo kecuali untuk konvensi penamaan. Sebagai contoh, saya pikir repositori yang diberikan di bawah ini sama dengan ProductsCommandHandler
dan mungkin satu perbedaan adalah bahwa tidak ada GetProduct
di sini yang biasanya kita tambahkan. Bisakah Anda menjelaskan apa yang tidak saya maksudkan di sini?
public class ProductRepository {
void AddNewProduct(Product newProduct) {
...
}
void RateProduct(int productId, int userId, int rating) {
var product = repository.Find(productId);
if (product != null)
{
product.RateProduct(userId, rating);
repository.Save(product);
}
}
}
⚠ Jangan edit bagian ini.
@martinmthomas Terima kasih atas pertanyaan Anda! Kami akan meninjau dan memberikan pembaruan yang sesuai.
@MikeWasson ada pemikiran di sini?
AB # 160217 - Terima kasih telah melaporkan - masalah ini sedang ditinjau
@martinmthomas Sebenarnya, penangan perintah bukan tempat penyimpanan. Ini menggunakan repositori.
Penangan perintah dimaksudkan untuk "memproses perintah yang sebenarnya, jika cocok". Dalam contoh kelas ProductsCommandHandler
menerima IRepository<Product>
dalam konstruktornya.
Katakanlah pengguna akan menilai produk 5555 hingga 4 bintang.
{"product":"5555","stars":4}
RateProduct
dan mengisi produk 5555, bintang 4. Dalam contoh ini juga mengisi siapa yang memberi peringkat.CommandHandler
di controller Anda (mungkin dengan injeksi ketergantungan) dan hanya menempatkan perintah di sana: h.Handle (c); di mana c adalah perintah RateProduct.Jadi 3 opsi: a) Dapatkan pawang, b) Dapatkan antrian, c) Dapatkan bus dan biarkan ia memutuskan untuk mengirim perintah ke pawang atau ke antrian.
Apapun pendekatan yang Anda lakukan ... perbedaan utama tentang "repositori klasik" adalah bahwa Anda TIDAK PERNAH menggunakan repositori itu sendiri di kontroler. Kontroler tidak "tahu tentang cara mengelola entitas" (repositori klasik) tetapi tahu "cara mengelola NIAT MELAKUKAN HAL ke entitas" (penangan perintah).
Maka itu adalah penangan perintah yang -seperti namanya- itu "menangani perintah" yang datang dari suatu tempat (pengontrol web html, pengontrol API, baris perintah, apa pun) yang dikirim sebagai maksud dan itu adalah CommandHandler (yang termasuk sisi tulis) yang memutuskan apa yang harus dilakukan dengan perintah itu.
Misalnya, CommandHandler dapat menggunakan repo untuk mendapatkan produk, menyetel status dan menyimpan (seperti dalam contoh), tetapi juga dapat menulis ke log peristiwa, memicu elemen untuk memperbarui sisi baca, memicu konektor eksternal, atau apa pun.
UI berbasis tugas pengguna untuk menilai produk dan pengontrolnya menjadi AGNOSTIK "di mana" sistem bintang / peringkat ditempatkan atau disimpan. Bayangkan Anda mendesain sistem dari awal dan kelas Produk sudah berisi metode RateProduct () seperti dalam contoh. Baik.
Tapi ... bagaimana jika Anda memiliki sistem warisan di sana dengan pendekatan "Lama" untuk Produk. Dalam "model" (yaitu: Business Mind) tidak ada "peringkat" produk. Sebaliknya orang pemasaran ingin "menambahkan" peringkat ke produk yang ada tetapi semua perusahaan setuju bahwa ini adalah "hal eksternal". Apakah Anda akan menggunakan repositori Produk? Atau mungkin penyimpanan pembantu lain sehingga Anda tidak "menyentuh" Product dan ProductRepository yang telah teruji sepenuhnya dan sudah teruji?
Jika Anda menggunakan perintah, tidak masalah bagi pengontrol penulisan. Web, API, dan CLI semuanya hanya akan mengirim "perintah" ke pengendali perintah (baik secara langsung, melalui antrian atau melalui bus perintah yang akan merutekan secara bergiliran ke penangan atau ke antrian) dan mereka lupa. Kemudian penangan perintah akan memutuskan apa yang harus dilakukan dengan "RateProductCommand" di titik kecil dan terpusat dari kode sumber Anda, ini memisahkan cara ini ditangani dari kode aplikasi, sehingga mendapatkan mantainability.
Kemudian penangan akan memutuskan apakah cocok menggunakan ProductRepository atau pendekatan lain apa pun untuk menyimpan "peringkat produk".
Jadi, untuk menjawab:
CommandHandler => tidak ada hubungannya dengan entitites. Ini menangani "niat pengguna" (yang pada akhirnya dapat mengubah entitas; jadi kemungkinan besar penangan perintah menggunakan repositori).
Repositori => penyimpanan sebenarnya untuk entitas tertentu.
Harapan untuk membantu.
Xavi.
Seperti yang disebutkan @xmontero , ProductsCommandHandler dan ProductRepository hanya memiliki relasi "memiliki". ProductsCommandHandler bertindak sebagai antarmuka antara ProductApi / Controller dan ProductRepository. Implementasi ini membantu menjaga agar perintah tetap terpisah dari Queries. Dalam pendekatan tradisional, kami langsung menggunakan repositori dari pengontrol yang menjaga menjalankan perintah dan Kueri bersama-sama sehingga tidak perlu antarmuka lain di antaranya.
Anda telah menerapkan pola desain CQRS dalam aplikasi Anda, jika Anda memisahkan Perintah dari Kueri. Ini membawa Anda ke arah mendapatkan semua manfaat CQRS yang disebutkan dalam artikel.
Komentar yang paling membantu
@martinmthomas Sebenarnya, penangan perintah bukan tempat penyimpanan. Ini menggunakan repositori.
Penangan perintah dimaksudkan untuk "memproses perintah yang sebenarnya, jika cocok". Dalam contoh kelas
ProductsCommandHandler
menerimaIRepository<Product>
dalam konstruktornya.Katakanlah pengguna akan menilai produk 5555 hingga 4 bintang.
{"product":"5555","stars":4}
RateProduct
dan mengisi produk 5555, bintang 4. Dalam contoh ini juga mengisi siapa yang memberi peringkat.CommandHandler
di controller Anda (mungkin dengan injeksi ketergantungan) dan hanya menempatkan perintah di sana: h.Handle (c); di mana c adalah perintah RateProduct.Jadi 3 opsi: a) Dapatkan pawang, b) Dapatkan antrian, c) Dapatkan bus dan biarkan ia memutuskan untuk mengirim perintah ke pawang atau ke antrian.
Apapun pendekatan yang Anda lakukan ... perbedaan utama tentang "repositori klasik" adalah bahwa Anda TIDAK PERNAH menggunakan repositori itu sendiri di kontroler. Kontroler tidak "tahu tentang cara mengelola entitas" (repositori klasik) tetapi tahu "cara mengelola NIAT MELAKUKAN HAL ke entitas" (penangan perintah).
Maka itu adalah penangan perintah yang -seperti namanya- itu "menangani perintah" yang datang dari suatu tempat (pengontrol web html, pengontrol API, baris perintah, apa pun) yang dikirim sebagai maksud dan itu adalah CommandHandler (yang termasuk sisi tulis) yang memutuskan apa yang harus dilakukan dengan perintah itu.
Misalnya, CommandHandler dapat menggunakan repo untuk mendapatkan produk, menyetel status dan menyimpan (seperti dalam contoh), tetapi juga dapat menulis ke log peristiwa, memicu elemen untuk memperbarui sisi baca, memicu konektor eksternal, atau apa pun.
UI berbasis tugas pengguna untuk menilai produk dan pengontrolnya menjadi AGNOSTIK "di mana" sistem bintang / peringkat ditempatkan atau disimpan. Bayangkan Anda mendesain sistem dari awal dan kelas Produk sudah berisi metode RateProduct () seperti dalam contoh. Baik.
Tapi ... bagaimana jika Anda memiliki sistem warisan di sana dengan pendekatan "Lama" untuk Produk. Dalam "model" (yaitu: Business Mind) tidak ada "peringkat" produk. Sebaliknya orang pemasaran ingin "menambahkan" peringkat ke produk yang ada tetapi semua perusahaan setuju bahwa ini adalah "hal eksternal". Apakah Anda akan menggunakan repositori Produk? Atau mungkin penyimpanan pembantu lain sehingga Anda tidak "menyentuh" Product dan ProductRepository yang telah teruji sepenuhnya dan sudah teruji?
Jika Anda menggunakan perintah, tidak masalah bagi pengontrol penulisan. Web, API, dan CLI semuanya hanya akan mengirim "perintah" ke pengendali perintah (baik secara langsung, melalui antrian atau melalui bus perintah yang akan merutekan secara bergiliran ke penangan atau ke antrian) dan mereka lupa. Kemudian penangan perintah akan memutuskan apa yang harus dilakukan dengan "RateProductCommand" di titik kecil dan terpusat dari kode sumber Anda, ini memisahkan cara ini ditangani dari kode aplikasi, sehingga mendapatkan mantainability.
Kemudian penangan akan memutuskan apakah cocok menggunakan ProductRepository atau pendekatan lain apa pun untuk menyimpan "peringkat produk".
Jadi, untuk menjawab:
CommandHandler => tidak ada hubungannya dengan entitites. Ini menangani "niat pengguna" (yang pada akhirnya dapat mengubah entitas; jadi kemungkinan besar penangan perintah menggunakan repositori).
Repositori => penyimpanan sebenarnya untuk entitas tertentu.
Harapan untuk membantu.
Xavi.