سؤال

I'm currently implementing the Command-Handler Pattern for a service I'm designing where the Command is essentially a DTO for the Handler's .Handle() method. Up to this point, it's all be rather straight forward but I've run into an implementation question that has me on the fence regarding it's smell.

Should I create interfaces that extend ICommand with the extra, specific data needed for their corresponding CommandHandler...or should I create a .Data property on the ICommand interface to access a nested Dto object?

Option #1

public interface ICommand
{
    Guid Id { get; set; }
    string Name { get; set; }
    CommandStatus Status { get; set; }
    TimeSpan Elapsed { get; set; }
}

[KnownType(typeof (DeleteProjectLogCommand))]
[DataContract(Name = "Command")]
public abstract class CommandBase : ICommand
{
    [DataMember]
    public Guid Id { get; set; }
    [DataMember]
    public string Name { get; set; }
    [DataMember]
    public CommandStatus Status { get; set; }
    [DataMember]
    public TimeSpan Elapsed { get; set; }
}

public interface IDeleteProjectCommand : ICommand
{
    long? ProjectId { get; set; }
}

[DataContract(Name = "DeleteProjectLogCommand")]
public class DeleteProjectLogCommand : CommandBase, IDeleteProjectCommand
{
    [DataMember]
    public long? ProjectId { get; set; }
}

Option #2

public interface ICommand
{
    Guid Id { get; set; }
    string Name { get; set; }
    CommandStatus Status { get; set; }
    TimeSpan Elapsed { get; set; }
    DataDto Data { get; set; }
}

[KnownType(typeof(ProjectDto))]
[DataContract(Name = "DataDto")]
public abstract class DataDto
{
    [DataMember]
    long? Id { get; set; }
    bool IsNew { get; set; }
}

public class ProjectDto : DataDto
{
    public long? OrganizationId { get; set;}
    public ProjectType ProjectType { get; set;}
    // ...etc
}

[DataContract(Name = "DeleteProjectLogCommand")]
public class DeleteProjectLogCommand : CommandBase
{
    // ...in this instance no other data is needed, 
    // making this basically just an empty Decorator of CommandBase
}

The second example is a little DRY'er, however it comes at the expense of having a fatter DataContracts and a slew of now-empty decorations of the abstract CommandBase that would have otherwise been implemented from more concise interfaces.

هل كانت مفيدة؟

المحلول

I think that the second option loses the essence of having specialized commands. You could as well rename DeleteProjectLogCommand to CRUDCommand. Furthermore, you are kind of restricting the capabilities of your implementation by introducing a generic DataDto payload into ICommand which by the way, might not be needed in many cases. And your ProjectDto is taking care of what should be your command properties.

I'd stick with your first option. Even more, I'd probably get rid of IDeleteProjectCommand to keep it simpler.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top