Komutun kendisinde yöntem yerine neden CommandHandler sınıfını Handle () ile ayırın


13

S # arp mimarisi kullanarak böyle uygulanan CQRS desen bir parçası var :

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;
    }
}

Neden sadece Commandveri ve işleme yöntemi içeren bir sınıf var merak ediyorum ? Komut işleme mantığını komut özelliklerinden ayrı olarak test etmeniz gereken bir tür test edilebilirlik avantajı mıdır? Yoksa, farklı uygulamalarla tek bir komuta sahip olmanız gereken sık sık bir iş gereksinimi mi var ICommandHandler<MyCommand, CommandResult>?


Ben de aynı soruyu sordum, bakmaya değer: blogs.cuttingedge.it/steven/posts/2011/…
rdhaundiyal

Yanıtlar:


14

Komik, bu soru bana mühendislerimizden biriyle üzerinde çalıştığım iletişim kütüphanesi hakkında yaptığım aynı konuşmayı hatırlattı.

Komutlar yerine, Request sınıfları ve sonra RequestHandlers vardı. Tasarım, tanımladığınız şeye çok benziyordu. Sanırım sahip olduğunuz karışıklığın bir kısmı, İngilizce "komut" kelimesini görmeniz ve anında "fiil, eylem ... vb."

Ancak bu tasarımda, Komuta'yı (veya İsteği) bir mektup olarak düşünün. Veya posta hizmetinin ne olduğunu bilmeyenler için e-postayı düşünün. Basitçe içeriktir, bu içeriğin nasıl davranılması gerektiğinden ayrılmıştır.

Neden bunu yaptın? Çoğu basit durumda, Komut Deseni'nin bir nedeni yoktur ve bu sınıfın doğrudan iş yapmasını sağlayabilirsiniz. Bununla birlikte, tasarımınızdaki gibi ayrıştırmanın yapılması, eyleminizin / komutunuzun / isteğinizin biraz mesafe kat etmesi gerektiğinde mantıklıdır. Örneğin, soketler veya borular boyunca veya alan ve altyapı arasında. Ya da mimarinizde komutlarınızın kalıcı olması gerekir (örn. Komut işleyicisi, bazı sistem olayları nedeniyle 200 komut geldiğinde ve ilk 40 işlem kapatıldıktan sonra bir seferde 1 komut yapabilir). Bu durumda, basit bir salt mesaj sınıfına sahip olmak, sadece mesaj kısmını JSON / XML / ikili / herhangi bir şekilde serileştirmek ve komut işleyicisi işlemeye hazır olana kadar boru hattından geçirmek çok basit hale gelir.

Command'ı CommandHandler'dan ayırmanın başka bir avantajı, şimdi paralel miras hiyerarşisi seçeneğinizin olmasıdır. Örneğin, tüm komutlarınız serileştirmeyi destekleyen bir temel komut sınıfından türetilebilir. Ve belki de çok fazla benzerliğe sahip 20 komut işleyicisinden 4'üne sahipsiniz, şimdi bunları gelen işleyici temel sınıfından türetebilirsiniz. Eğer bir sınıfta veri ve komut yönetimi yapacak olsaydınız, bu tür bir ilişki hızla kontrolden çıkardı.

Ayrıştırma için başka bir örnek, komutunuz çok az girdi gerektiriyorsa (örneğin 2 tamsayı ve bir dize), ancak işleme mantığı, ara üye değişkenlerinde veri depolamak istediğiniz yerde yeterince karmaşıktı. 50 komutu kuyruğa alırsanız, tüm bu ara depolama için bellek ayırmak istemezsiniz, bu nedenle Command'ı CommandHandler'dan ayırırsınız. Şimdi 50 hafif veri yapısını kuyruğa alıyorsunuz ve daha karmaşık veri depolaması, komutları işleyen CommandHandler tarafından yalnızca bir kez (veya N işleyiciniz varsa N kez) ayrılıyor.


Mesele şu ki, bu bağlamda, komut / istek uzak / kalıcı / vb. Değildir. Doğrudan ele alınır. Ve ikisini birbirinden ayırmanın mirasa nasıl yardımcı olacağını göremiyorum. Aslında daha da zorlaştırırdı. Son paragraf da bir çeşit özledim. Nesne oluşturma pahalı bir işlem değildir ve 50 komut ihmal edilebilir sayıdır.
Euphoric

@Euphoric: Bağlamın ne olduğunu nereden biliyorsun? S # arp Mimarisi özel bir şey olmadığı sürece, tüm gördüğüm birkaç sınıf bildirimi ve uygulamanın geri kalanında nasıl kullanıldıkları hakkında hiçbir fikriniz yok. 50 gibi seçtiğim sayıları beğenmediyseniz, saniyede 50 gibi bir şey seçin. Bu yeterli değilse, saniyede 1000 seçin. Sadece örnek vermeye çalışıyordum. Yoksa bu bağlamda çok fazla komuta sahip olacağını düşünmüyor musunuz?
DXM

Örneğin, tam yapı burada weblogs.asp.net/shijuvarghese/archive/2011/10/18/… . Ve hiçbir yerde söylediklerini söylemiyor. Ve hız hakkında sorun, profil oluşturmadan 'performans' argümanını kullanmanızdır. Böyle bir düşünce için gereksinimleriniz varsa, genel mimari kullanmayacaksınız, ancak daha özel bir şey inşa edeceksiniz.
Euphoric

1
Bu son noktanız olup olmadığına bakayım: OP örnek istedi, örneğin önce basit yolu tasarladınız ve uygulamanız çalışıyor, sonra ölçeklendiriyorsunuz ve komut kalıbı kullandığınız yerleri genişletiyorsunuz, canlı yayına başlarsınız ve sunucunuzla konuşan 10.000 makineye sahip olursunuz ve sunucunuz hala orijinal mimarinizi kullanır, ardından sorunu profillendirir ve tanımlarsınız ve komut verilerini komut işleminden ayırabilirsiniz, ancak yalnızca siz profil oluşturduktan sonra. Bunların hepsini cevaba eklesem seni gerçekten mutlu eder mi? Bir örnek istedi, ona bir tane verdim.
DXM

... bu yüzden sadece sizin gönderdiğiniz blog yazısı üzerinden baktım ve yazdıklarım ile aynı hizaya geliyor gibi görünüyor: komutunuz biraz mesafe kat etmek zorunda kalırsa onları ayırın. Blogda temelde sadece başka bir boru, soket, mesaj kuyruğu, esb ... vs olan bir komut veriyoluna atıfta bulunuyor gibi görünüyor
DXM

2

Normal komut düzeni , veri ve davranışın tek sınıfta olmasıyla ilgilidir. Bu tür 'Komut / İşleyici kalıbı' biraz farklıdır. Normal desene kıyasla tek avantaj, komutunuzun çerçevelere bağlı olmamasının avantajıdır. Örneğin, komutunuzun DB erişimine ihtiyacı olabilir, bu nedenle bir çeşit DB bağlamına veya oturumuna sahip olması gerekir, yani çerçevelere bağlıdır. Ancak bu komut alan adınızın bir parçası olabilir, bu nedenle Bağımlılık Ters Çevirme İlkesine göre çerçevelere bağımlı olmasını istemezsiniz . Giriş ve çıkış parametrelerini davranıştan ayırmak ve bunları bağlamak için bazı dağıtıcıya sahip olmak bunu düzeltebilir.

Öte yandan, hem mirasın hem de komutların kompozisyonunun avantajını kaybedeceksiniz. Bence bu gerçek güç.

Ayrıca, küçük nitpick. Command adında olması onu CQRS'nin bir parçası yapmaz. Bu çok daha temel bir şeyle ilgili. Bu tür yapı aynı anda hem komut hem de sorgu olarak kullanılabilir.


Weblogs.asp.net/shijuvarghese/archive/2011/10/18/… bağlantısını gördüm , ancak işaret ettiğim S # arp Arch kodunda herhangi bir otobüs belirtisi görmüyorum. Yani, sanırım, benim durumumdaki böyle bir ayrım sadece sınıfları yayar ve mantığı sıçratır.
rgripper


Hmm, işaret ettiğin için teşekkürler. Sonra benim durumum biraz daha kötü, çünkü kodda ICommandProcessor IOC'ed ve CommandProcessor (ki kendisi de komut işleyicileri için bir IOC yapıyor) - çamurlu bir kompozisyon çözüldü. Ve projede, bir komuta için birden fazla hadler için iş vakası yok gibi görünüyor.
rgripper
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.