Mengapa pisahkan class CommandHandler dengan Handle () alih-alih metode penanganan di Command itu sendiri

13

Saya memiliki bagian dari pola CQRS yang diimplementasikan menggunakan Arsitektur S # arp seperti ini:

public class MyCommand
{
    public CustomerId { get; set; }

    // some other fields
}

public class MyCommandHandler<MyCommand> : ICommandHandler<MyCommand, CommandResult>
{
    Handle(MyCommand command)
    {
        // some code for saving Customer entity

        return CommandResult.Success;
    }
}

Saya bertanya-tanya mengapa tidak hanya kelas yang Commandberisi data dan metode penanganan? Apakah ini semacam manfaat testabilitas, di mana Anda perlu menguji logika penanganan perintah secara terpisah dari properti perintah? Atau itu beberapa persyaratan bisnis yang sering, di mana Anda perlu memiliki satu perintah ditangani oleh implementasi yang berbeda ICommandHandler<MyCommand, CommandResult>?

rgripper
sumber
Saya memiliki pertanyaan yang sama, layak untuk dilihat: blogs.cuttingedge.it/steven/posts/2011/…
rdhaundiyal

Jawaban:

14

Lucu, pertanyaan ini hanya mengingatkan saya pada percakapan yang persis sama saya miliki dengan salah satu insinyur kami tentang perpustakaan komunikasi yang saya kerjakan.

Alih-alih perintah, saya punya kelas Permintaan dan kemudian saya punya RequestHandlers. Desainnya sangat mirip dengan apa yang Anda gambarkan. Saya pikir bagian dari kebingungan yang Anda miliki adalah bahwa Anda melihat kata "perintah" dalam bahasa Inggris, dan langsung berpikir "kata kerja, tindakan ... dll".

Namun dalam desain ini, pikirkan Command (atau Request) sebagai surat. Atau bagi mereka yang tidak tahu apa itu layanan pos, pikirkan e-mail. Ini hanyalah konten, dipisahkan dari bagaimana konten itu harus ditindaklanjuti.

Mengapa kamu melakukan ini? Dalam kebanyakan kasus sederhana, dari Pola Perintah tidak ada alasan dan Anda bisa membuat kelas ini melakukan pekerjaan secara langsung. Namun, melakukan decoupling seperti dalam desain Anda masuk akal jika tindakan / perintah / permintaan Anda harus menempuh jarak. Misalnya, melintasi, soket atau pipa, atau antara domain dan infrastruktur. Atau mungkin dalam arsitektur Anda, perintah Anda harus persisten (mis. Penangan perintah dapat melakukan 1 perintah pada satu waktu, karena beberapa kejadian sistem, 200 perintah tiba dan setelah proses 40 pertama dimatikan). Dalam hal itu, memiliki kelas pesan-saja yang sederhana, menjadi sangat sederhana untuk membuat serialisasi hanya bagian pesan ke dalam JSON / XML / binary / apa pun dan meneruskannya ke saluran pipa sampai penangan perintahnya siap memprosesnya.

Keuntungan lain dari decoupling Command dari CommandHandler adalah sekarang Anda memiliki opsi hierarki pewarisan paralel. Misalnya, semua perintah Anda dapat berasal dari kelas perintah dasar yang mendukung serialisasi. Dan mungkin Anda memiliki 4 dari 20 penangan perintah yang memiliki banyak kesamaan, sekarang Anda dapat mengambilnya dari kelas dasar penangan yang datang. Jika Anda memiliki data dan penanganan perintah dalam satu kelas, tipe hubungan ini akan cepat lepas kendali.

Contoh lain untuk decoupling adalah jika perintah Anda membutuhkan input yang sangat sedikit (misalnya 2 integer dan string) namun logika penanganannya cukup kompleks di mana Anda ingin menyimpan data dalam variabel anggota perantara. Jika Anda mengantri hingga 50 perintah, Anda tidak ingin mengalokasikan memori untuk semua penyimpanan perantara tersebut, sehingga Anda memisahkan Command dari CommandHandler. Sekarang Anda mengantri hingga 50 struktur data ringan dan penyimpanan data yang lebih kompleks dialokasikan hanya sekali (atau N kali jika Anda memiliki N handler) oleh CommandHandler yang memproses perintah.

DXM
sumber
Intinya adalah, bahwa dalam konteks ini, perintah / permintaan tidak jauh / tetap / dll. Itu ditangani secara langsung. Dan saya tidak bisa melihat bagaimana memisahkan keduanya akan membantu pewarisan. Itu sebenarnya akan membuatnya lebih sulit. Paragraf terakhir juga agak ketinggalan. Pembuatan objek bukanlah operasi yang mahal dan 50 perintah adalah angka yang dapat diabaikan.
Euforia
@ Euphoric: bagaimana Anda tahu konteksnya? Kecuali jika Arsitektur S # arp adalah sesuatu yang istimewa, yang saya lihat adalah beberapa deklarasi kelas dan Anda tidak tahu bagaimana mereka digunakan dalam aplikasi lainnya. Jika Anda tidak menyukai angka yang saya pilih seperti 50, pilih sesuatu seperti 50 per detik. Jika itu tidak cukup, pilih 1000 per detik. Saya hanya berusaha memberikan contoh. Atau Anda tidak berpikir dalam konteks ini dia akan memiliki banyak perintah?
DXM
Sebagai contoh, struktur yang tepat terlihat di sini weblogs.asp.net/shijuvarghese/archive/2011/10/18/… . Dan tidak ada yang mengatakan apa yang Anda katakan. Dan soal kecepatan, masalahnya adalah Anda menggunakan argumen 'kinerja' tanpa membuat profil. Jika Anda memiliki persyaratan untuk throughtput seperti itu, Anda tidak akan menggunakan arsitektur generik tetapi membangun sesuatu yang lebih khusus.
Euforia
1
Biarkan saya melihat apakah ini poin terakhir Anda: OP meminta contoh, dan saya seharusnya mengatakan, misalnya, pertama Anda merancang cara sederhana dan aplikasi Anda berfungsi, kemudian Anda meningkatkan dan memperluas tempat di mana Anda menggunakan pola perintah, lalu Anda ditayangkan dan Anda mendapatkan 10.000 mesin berbicara dengan server Anda dan server Anda masih menggunakan arsitektur asli Anda, kemudian Anda profil dan mengidentifikasi masalah, dan kemudian Anda dapat memisahkan data perintah dari penanganan perintah, tetapi hanya setelah profil Anda. Apakah itu benar-benar membuat Anda lebih bahagia jika saya memasukkan semua itu dalam jawaban? Dia meminta contoh, saya memberinya satu.
DXM
... jadi saya hanya melihat sekilas pada posting blog yang Anda posting dan tampaknya sesuai dengan apa yang saya tulis: pisahkan mereka jika perintah Anda harus menempuh jarak yang cukup jauh. Di blog dia sepertinya merujuk ke command bus yang pada dasarnya hanyalah pipa, soket, antrian pesan, esb ... dll
DXM
2

Pola perintah normal adalah tentang memiliki data dan perilaku dalam kelas tunggal. 'Pola Command / Handler' semacam ini sedikit berbeda. Satu-satunya keuntungan dibandingkan dengan pola normal adalah keuntungan tambahan karena tidak memiliki perintah Anda bergantung pada kerangka kerja. Misalnya, perintah Anda mungkin memerlukan akses DB sehingga harus memiliki semacam konteks atau sesi DB, artinya tergantung pada kerangka kerja. Tetapi perintah ini mungkin menjadi bagian dari domain Anda, jadi Anda tidak ingin itu bergantung pada kerangka kerja menurut Prinsip Ketergantungan Inversi . Memisahkan parameter input dan output dari perilaku dan memiliki beberapa operator untuk memasang mereka dapat memperbaikinya.

Di sisi lain, Anda akan kehilangan keuntungan baik dari pewarisan maupun komposisi perintah. Yang saya pikir itu adalah kekuatan sejati.

Juga, nitpick kecil. Hanya karena memiliki perintah atas nama tidak menjadikannya bagian dari CQRS. Itu tentang sesuatu yang jauh lebih mendasar. Struktur semacam ini dapat berfungsi baik sebagai perintah dan sebagai permintaan bahkan pada saat yang sama.

Euforia
sumber
Saya telah melihat tautan weblogs.asp.net/shijuvarghese/archive/2011/10/18/... Anda telah menunjukkan, tapi saya tidak melihat tanda-tanda bus di S # arp Arch kode yang saya miliki. Jadi, saya kira, pemisahan seperti itu dalam kasus saya hanya menyebarkan kelas dan memercikkan logika.
rgripper
Hmm, terima kasih sudah menunjukkan. Maka kasus saya bahkan sedikit lebih buruk, karena dalam kode saya punya ICommandProcessor adalah IOC'ed dan diselesaikan ke CommandProcessor (yang dengan sendirinya membuat IOC untuk penangan perintah) - komposisi berlumpur. Dan dalam proyek tersebut tampaknya tidak ada kasus bisnis untuk lebih dari satu pengembara untuk suatu perintah.
rgripper