I am implementing CQRS pattern. To use CQRS pattern in my project I wrote three commands, they are
public class DogCommand : PetCommand
{
public DogCommand(){}
public override string Name{get; set;}
}
public class CatCommand : PetCommand
{
public CatCommand(){}
public override string Name{get; set;}
}
public abstract class PetCommand : ICommand
{
public PetCommand(){}
public virtual string Name{get; set;}
}
public interface ICommand
{
//Business logic
}
Here I have interface called ICommand
. PetCommand is base class which is implementing this interface. Derived class DogCommand
and CatCommand
are inheriting PetCommand
.
I also wrote base command handler, as below
public abstract class BaseCommandHandler<T> : CommandHandler<T> where T : ICommand
{
protected BaseCommandHandler(string type, string name): base(type, name)
{
}
}
public abstract class CommandHandler<T> : ICommandHandler<T> where T : ICommand
{
protected CommandHandler(string type, string name)
{
//Business logic
}
protected void LogWrite(T command)
{
//Writing log
}
}
public interface ICommandHandler<in T> where T : ICommand
{
void Run(T command);
}
All functions present in BaseCommandHandler
, I will use in each derived command handler
Now problem is in derived class command handler
public class PetCommandHandler : BaseCommandHandler<DogCommand>, ICommandHandler<CatCommand>
{
public void Run(DogCommand dCommand)
{
this.LogWrite(dCommand)
}
public void Run(CatCommand cCommand)
{
**//Want to access this.LogWrite() with cCommand. How can I do that?**
}
}
Here I am unable to access this.LogWrite()
function for cCommand, because PetCommandHandler
is inheriting first BaseCommandHandler
and then implementing ICommandHandle.
How to access
this.LogWrite()
function for cCommand?
Here is compile time error:
cannot convert from ‘Command.DogCommand’ to ‘Command.CatCommand’
Update :
First way to fix this issue :
I can fix this issue by using base command i.e PetCommand
in BaseCommandHandler
instead of DogCommand
. This will help me to access all derived classes in this.LogWrite()
function, but this will lead me to implement empty Run(PetCommand petCommand) {}
function, that I don't want to do.
Second way :
I can change LogWrite()
function as virtual
in CommandHandler
and override
whenever I face this situation.
I really appreciate if someone provide me any other solution for this issue.
You have a design issue to resolve.
You are trying to handle Two separate Types in the generic class. This is not a extensible design.
When there will be a new class inheriting from PetCommand
created, you will have to change PetCommand handler class to implement interface ICommandHandler<newPetCommand>
. That's basically a bad design.
The command handler class of yours should deal with the Pet, not with a specific type of Pet such as Cat or Dog.
You need to have CommandHandler and PetCommandHandler class as following.
public abstract class CommandHandler<T> : ICommandHandler<T> where T : ICommand
{
protected CommandHandler(string type, string name)
{
//Business logic
}
//Making Run method abstract so that
//individual Handler class can have their own logic in it.
public abstract void Run(T command);
//Common implementation for LogWrite.
//If this also requires override, it can be made virtual
//so that deriving class can override the logic.
protected void LogWrite(T command)
{
//Writing log
}
}
//PetCommandHandler class now can be used for any class object
//which is inheriting PetCommand class.
public class PetCommandHandler<T> : BaseCommandHandler<T> where T: PetCommand
{
public PetCommandHandler(string type, string name) : base(type, name)
{
}
public override void Run(T dCommand)
{
this.LogWrite(dCommand);
}
}
How to test?
var dog = new DogCommand();
var commandHandler = new PetCommandHandler<DogCommand>("Dog", "Tom");
commandHandler.Run(dog);
var cat = new CatCommand();
var catHandler = new PetCommandHandler<CatCommand>("Cat", "Mini");
catHandler.Run(cat);
If you later introduce new PetCommand
class, let say PandaCommand
. You can still use PetHandler as following.
var pandaHandler = new PetHandler<PandaCommand>("Panda", "Po");
var panda = new PandaCommand();
pandaHandler.Run(panda);
If you do not want to create separate instance of PetCommandHandler
for different PetCommand type. You can change the PetCommandHandler class as following.
public class PetCommandHandler : BaseCommandHandler<PetCommand>
{
public PetCommandHandler(string type, string name) : base(type, name)
{
}
public override void Run(PetCommand dCommand)
{
this.LogWrite(dCommand);
}
}
With this class you just need to create only one instance of PetCommndHandler
and you can execute Run
method with any object of PetCommand
var patCommandHandler = new PetCommandHandler("someType", "someName");
patCommandHandler.Run(dog);
patCommandHandler.Run(cat);
patCommandHandler.Run(panda);
I hope this will help you resolve your issue.