2015-06-30 2 views
3

В большинстве примеров, которые я видел, команды и события представлены как классы. Это означает, что вам нужно написать класс CorrectNameCommand с именем name и классом NameCorrectedEvent с свойством name. Учитывая, что обе команды и события в большинстве случаев сериализуются и десериализуются и отправляются другим сторонам (идет безопасность типа времени компиляции), в чем преимущество этих явных классов над более общим классом?Команды и события CQRS как общие классы?

Пример:

Командная класс с именем (который представляет тип команды), ключ от AG, который должен обрабатывать команду и массив объектов или пар имя/значение для любого другие параметры.

Класс событий по существу тот же (возможно, мы можем поместить общие части в класс CommandEventBase).

Обработчики команд (и событий) теперь должны проверять имя команды (события) вместо своего типа класса и должны полагаться на правильность параметров в списке (например, десериализатор должен полагаться на то, что сериализованный формат является правильным).

Это хороший подход? Если да, то почему он не используется в образцах и учебниках? Если нет, то в чем проблемы?

+1

Я бы сказал, что речь идет о читаемости и явлении. Вы видите, что требуется Command, и вы видите, что предоставляет событие. Пары Key-Value-P здесь не очень помогают. Также, используя соглашения об именах, легко использовать Ioc-Container для создания правильного Command- и EventHandler. – Jehof

+0

Так что это компромисс? Я также написал общий обработчик команд, который автоматически отправляет метод с совпадающим именем и соответствующими параметрами в аг. Это устраняет даже работу по написанию обработчика команд для каждой команды (но не запрещает). –

+0

Означает ли это, что у вас есть один большой класс со многими методами для обработки ваших команд? Вместо 1 класса обрабатывает каждую команду? –

ответ

6

Дублирование

Это справедливое замечание, что, когда команды и события упорядочиваются, время компиляции безопасность теряется, но в статически типизированный язык, я бы до сих пор предпочитают сильно типизированных команды и типы событий.

Причина этого в том, что она дает вам единую базу кода, отвечающую за интерпретацию элементов сообщения. Сериализация имеет тенденцию быть вполне (тип) безопасной; десериализация - это то, где вы можете столкнуться с проблемами.

Тем не менее, я бы предпочел разобраться с любыми подобными проблемами в одном месте вместо того, чтобы распространяться по всей базе кода.

Это особенно актуально для событий, поскольку у вас может быть несколько обработчиков событий, обрабатывающих однотипные события. Если вы рассматриваете события как слабо типизированные словари, вам нужно будет дублировать реализацию Tolerant Reader в каждом обработчике событий.

С другой стороны, если вы обрабатываете события и команды как сильные типы, ваш десериализатор может быть единственным толерантным читателем, который вам нужно будет поддерживать.

Типы

Все это говорит, я могу понять, почему вы, в таких языках, как C# или Java, найти, что определение неизменные DTOs для каждого и каждое сообщение, кажется, как много накладных расходов:

public sealed class CorrectNameCommand 
{ 
    private readonly string userId; 
    private readonly string newName; 

    public CorrectNameCommand(string userId, string newName) 
    { 
     this.userId = userId; 
     this.newName = newName; 
    } 

    public string UserId 
    { 
     get { return this.userId; } 
    } 

    public string NewName 
    { 
     get { return this.newName; } 
    } 

    public override bool Equals(object obj) 
    { 
     var other = obj as UserName; 
     if (other == null) 
      return base.Equals(obj); 

     return object.Equals(this.userId, other.userId) 
      && object.Equals(this.newName, other.newName); 
    } 

    public override int GetHashCode() 
    { 
     return this.userId.GetHashCode()^this.newName.GetHashCode(); 
    } 
} 

Это, действительно, похоже на работу.

Именно по этой причине я в эти дни предпочитаю другие языки для реализации CQRS. Вкл.NET, F # является идеальным решением, потому что все выше коды сводится к этому однострочнику:

type CorrectNameCommand = { UserId : string; NewName : string } 

Вот что я хотел бы сделать, вместо передачи слабо типизированных словари вокруг. В последний раз, когда я услышал, что Грег Янг говорил о CQRS (NDC Oslo 2015), он, похоже, «преобразовал» в F #.

+0

Преобразование в F # - это не короткое время для меня. :-) Так что, возможно, золотой способ будет использовать что-то вроде того, что вы написали в F # как DSL и сгенерировали C#. –

+2

Вы считали, что просто определяете типы в F # и упаковываете их в библиотеку? Из C# эти записи будут выглядеть неизменными классами (по существу неотличимыми от класса CorrectNameCommand в моем примере на C#, вот что они компилируют). –

+0

Хорошая идея. Я дам ему попробовать. Спасибо. –