Question

I am pretty new to programming languages and only have limited knowledge about design patterns, so I hope you can help me with the following problem:

I have an application that operates on a group of different services. One functionality of the application is, to provide an interface to the user to call every method of the available services. Therefore I want to use the Command pattern because it allows me to add new commands just by adding new classes and not by changing the existing code. The parameters for each service command are passed to the constructor.

Commands:

public interface ICommand {
    void Execute();
}

public abstract class Command<T> : ICommand {
    public T Service { get; set; }

    public abstract void Execute() { /* use service */ }
}

public class Command1 : Command<Service1> {
    T1 param1;
    ...

   public Command1(T1 param1, ...) { /* set parameters */ }

   public override void Execute() { /* call first service1 method */ }
}

...

public class Command2 : Command<Service2> {
    T2 param1;

    ...

   public override void Execute() { /* call first service2 method */ }
}

...

The advantage is, that the user can instantiate a group of commands without knowing the application's interface and execute them at a later time when the service was set. The problem is, that I don't know how I can elegantly inject the services.
The application is mainly responsible for starting and stopping the services and keeping an instance of each service in a central place.

Application:

public class Application {
    S1 Service1;
    S2 Service2,
    ...

    public void StartService(/* params */) { /* ... */ }
    public void StopService(/* params */) { /* ... */ }
    ...
}

Question:

So my question is how do I get the correct service inside a command?
I thought about using some kind of Dependency injection, Service locator or Builder pattern, but I never used these patterns and I am not sure what's the best solution in this case and how to implement it correctly.

Update:

Thanks to the comment of @Andy and @Anders it's probably the best solution to use a Command class for my parameters and a CommandHandler class for the logic. The advantage is, that I can instantiate a command handler inside the Application class and pass the correct service in the handler's constructor. Also, I can create a command outside the Application without knowing the service a pass this command to the Application for execution.
To map commands to the correct command handler I a CommmandBus as suggested by @Andy, but I have some trouble implementing the java example in C# because there is no template map like Map<Class<? extends CommandHandler<?>>, CommandHandler<? extends Command>> in C#.

So what's a clean solution to map a command to its handler in C#? I don't really like my solution below because I have to upcast the command.

My updated code:

public interface ICommand { }

public class ConcreteCommand : ICommand {
    public Type1 Param1 { get; set; }
    public Type2 Param2 { get; set; }
    /* some more parameters */
}

public interface ICommandHandler<in TCommand> {
    Task Handle(TCommand command);
}

public class ConcreteCommandHandler : ICommandHandler<ConcreteCommand> {
    private readonly S1 service;

    public ConcreteCommandHandler(S1 service) {
        this.service = service;
    }

    public Task Handle(ConcreteCommand command) {
        return service.DoSomething(command.Param1, ...);
    }
}


public class CommandBus {
    /* BAD: Return type of command handler hardcoded */
    private readonly IDictionary<Type, Func<ICommand, Task>> handlerMap = new Dictionary<Type, Func<ICommand, Task>>();

        public void RegisterCommandHandler<TCommand>(ICommandHandler<TCommand> handler) where TCommand: ICommand
        {
            Type commandType = typeof(TCommand);

            if (handlerMap.ContainsKey(commandType))
                throw new HandlerAlreadyRegisteredException(commandType);

            /* BAD: Narrowing cast */
            handlerMap.Add(commandType, command => handler.Handle((TCommand) command));
        }

        public Task Dispatch<TCommand>(TCommand command) where TCommand : ICommand
        {
            Type commandType = typeof(TCommand);

            if (!handlerMap.TryGetValue(commandType, out Func<ICommand, Task> handler))
                throw new HandlerNotRegisteredException(commandType);

            return handler(command);
        }
}


public class Application {
    private CommandBus bus;
    private S1 service1;
    private S2 service2;
    ...

    private void InitializeBus() {
        bus.RegisterCommandHandler(new ConcreteCommandHandler(service1))
        ...
    }

    public void ExecuteCommand<TCommand>(TCommand command) where TCommand : ICommand {
        bus.Dispatch(command);
    }

    ...
}
Was it helpful?

Solution

Before answering your question, one should firstly know the goal developers are trying to achieve with the command pattern in the first place. More often than not, the pattern's purpose is to decouple modules from each other and to provide a sensible abstraction for execution of intents (commands) to the system.

In order to understand how commands fit into an application, let's integrate the command pattern by refactoring a hypothetical application which allows users to be registered. I apologise for the Java language, I haven't programmed in C# for a long time. In this very simple application we have a service and a controller:

class UserService {
    private UserRepository userRepository;
    private PasswordHashService passwordHashService;

    public User registerUser(
        String firstName,
        String lastName,
        String email,
        String passwordInPlainText
    ) {
        User userToBeRegistered = new User();
        userToBeRegistered.setId(userRepository.retrieveNewId());
        userToBeRegistered.setFirstName(firstName);
        userToBeRegistered.setLastName(lastName);
        userToBeRegistered.setEmail(email);
        userToBeRegistered.setPassword(passwordHashService.hash(passwordInPlainText));

        userRepository.save(userToBeRegistered);

        return userToBeRegistered;
    }
}

class UserController {
    private UserService userService;

    public Response<User> registerUser(FormInput formInput) {
        return new Response<>(userService.registerUser(
            formInput.getString("first_name"),
            formInput.getString("last_name"),
            formInput.getString("email"),
            formInput.getString("password")
        ));
    }
}

On the service layer, there's a design issue. The method takes 4 string arguments in a very specific order. This couples the caller of the method to the service and refactoring the method by adding a new optional argument might could end up being difficult if you called the registerUser from multiple places.

In order to reduce the number of arguments of the service method, let's introduce a special DTO object, acting as a data messenger between the two layers, and for the same of convenience, name it RegisterUserCommand. The Object would have the following structure:

class RegisterUserCommand {
    private String firstName;
    private String lastName;
    private String email;
    private String passwordInPlainText

    // getters and setter are omitted
}

which will lead to design change of the service method, now looking like this:

public User registerUser(RegisterUserCommand command) {
    User userToBeRegistered = new User();
    userToBeRegistered.setId(userRepository.retrieveNewId());
    userToBeRegistered.setFirstName(command.getFirstName());
    userToBeRegistered.setLastName(command.getLastName());
    userToBeRegistered.setEmail(command.getEmail());
    userToBeRegistered.setPassword(passwordHashService.hash(
        command.getPasswordInPlainText()
    ));

    userRepository.save(userToBeRegistered);

    return userToBeRegistered;
}

and the controllers method would change to:

public Response<User> registerUser(FormInput formInput) {
    RegisterUserCommand command = new RegisterUserCommand();
    command.setFirstName(formInput.getString("first_name"));
    command.setLastName(formInput.getString("last_name"));
    command.setEmail(formInput.getString("email"));
    command.setPasswordInPlainText(formInput.getString("password"));

    return new Response<>(userService.registerUser(command));
}

This fixes the unnecessary argument positional coupling, making it easier to introduce optional arguments to the user registration method by simply adding a new attribute to the command objects. In places where you don't work with the optional argument, no changes are necessary at all, in other places you may utilise the newly added property.

However the current design still contains coupling between the controller and the service. In this case, I wouldn't say it's a huge problem but since we're discussing a full command pattern integration, we'll refactor the code a bit further.

Introduction of a command bus

Using the command pattern without having some variant of a command bus is pretty meaningless. But what is this command bus? In short, it's mostly a glorified service locator. Some advanced implementations of command buses allow you to use plugins, middle-wares, effectively giving you the ability to extend the functionality of the command bus execution process without having to know it's internals.

Command busses generally consist of two main parts:

  1. service registry (some internal collection where instances of services live),
  2. command to service mapping (configuration telling which command type should be processed by which service).

Both of those two parts need to be configured by you. The 1. part requires you to somehow provide service instances to the command bus, and the 2. part requires you defining the mapping.

A very basic command bus implementation (really basic, no support for plugins etc.) could look like this:

interface Command {
}

interface CommandHandler<T extends Command> {
    Object execute(T command);
}

class CommandBus {
    private Map<Class<? extends CommandHandler<?>>, CommandHandler<? extends Command>> commandHandlers;
    private Map<Class<? extends Command>, Class<? extends CommandHandler<?>>> commandToHandlerConfig;

    public CommandBus() {
        commandHandlers = new HashMap<>();
        commandToHandlerConfig = new HashMap<>();
    }

    public void registerCommandHandler(CommandHandler<? extends Command> handler) {
        Class<CommandHandler<?>> clazz = (Class<CommandHandler<?>>) handler.getClass();

        if (commandHandlers.containsKey(clazz)) {
            throw new RuntimeException("The command handler " + clazz + " is already registered.");
        }

        commandHandlers.put(clazz, handler);
    }

    public void registerCommandToCommandHandler(
            Class<? extends Command> command,
            Class<? extends CommandHandler<?>> handler
    ) {
        if (!commandHandlers.containsKey(handler)) {
            throw new RuntimeException("The command handler " + handler + " is not registered.");
        }

        commandToHandlerConfig.put(command, handler);
    }

    public <T extends Command, U> U dispatch(T command, Class<U> resultClass) {
        Class<?> commandClass = command.getClass();

        if (!commandToHandlerConfig.containsKey(commandClass)) {
            throw new RuntimeException(
                    "The command " + commandClass + " could not be executed, no handler is configured."
            );
        }

        Class<? extends CommandHandler<?>> handlerClass = commandToHandlerConfig.get(commandClass);
        CommandHandler<? super Command> handler = (CommandHandler<? super Command>) commandHandlers.get(handlerClass);

        return resultClass.cast(handler.execute(command));
    }
}

This command bus allows you to register a command handler to a registry (fulfilling the 1. part) and to provide mapping for a given command to a certain handler (fulfilling the 2. part). Besides that it allows you to execute a command with an expected result class.

As a part of implementation, you may have noticed that that we've also introduced two interfaces, Command and CommandHandler. Those are necessary in compiled languages, but could be theoretically omitted in dynamic languages such as PHP or Python (as long as you'd follow certain guidelines defined by the command bus' implementation - mainly the method of the execution method of a handler).

Simple integration of our command bus

First we have to make our RegisterUserCommand implement the Command interface:

class RegisterUserCommand implements Command {
    // [...] the rest remains the same
}

then we make the UserService implement the CommandHandler interface, i.e. we need to add an appropriate execute method implementation. For the sake of simplicity, let's change our current registerUser method to the execute method.

class UserService implements CommandHandler<RegisterUserCommand> {
    // [...] the rest remains the same

    public Object execute(RegisterUserCommand command) {
        // [...] the rest remains the same
    }
}

These changes have been basically made so that the command and the service may be used in our command bus context. Right now you may have noticed a caveat. A class may only implement a generic interface only once, which forces you to basically have one command handler for each command. While you might find this troublesome at the beginning, in the long run this is actually very nice, since you'll end up with many tiny command handlers, each having only a single responsibility - handling a specific command instance.

A very basic integration of our command bus on the controller level could then look like the following (without actually making too much sense at the moment):

public Response<User> registerUser(FormInput formInput) {
    RegisterUserCommand command = new RegisterUserCommand();
    command.setFirstName(formInput.getString("first_name"));
    command.setLastName(formInput.getString("last_name"));
    command.setEmail(formInput.getString("email"));
    command.setPasswordInPlainText(formInput.getString("password"));

    CommandBus commandBus = new CommandBus();
    commandBus.registerCommandHandler(userService);
    commandBus.registerCommandToCommandHandler(
        RegisterUserCommand.class,
        userService.getClass()
    );

    return new Response<>(commandBus.dispatch(command, User.class));
}

Here we have manually created an instance of the command bus, registered a command handler and a command to handler mapping, basically forcing the command bus acting as a proxy. In reality, in big application there would usually be at most a few instances of a few separate command busses (or perhaps even only a single instance), which would come pre-configured, already containing all registered handlers and mappings, and such configured command bus would be injected, turning your controller into the following:

class UserController {
    private CommandBus commandBus;

    public Response<User> registerUser(FormInput formInput) {
        RegisterUserCommand command = new RegisterUserCommand();
        command.setFirstName(formInput.getString("first_name"));
        command.setLastName(formInput.getString("last_name"));
        command.setEmail(formInput.getString("email"));
        command.setPasswordInPlainText(formInput.getString("password"));

        return new Response<>(commandBus.dispatch(command, User.class));
    }
}

Thanks to this, you are no longer coupled to the UserService and the mapping is done on an infrastructure level (through configuration). This can be beneficial as it reduces number of dependencies of services, should a single service/controller/command handler invoke multiple commands.

The configuration could be e.g. a YAML, looking e.g. like this:

- CommandBus:
  - Handlers:
    - RegisterUser: UserService
    - SomeOtherCommand: SomeOtherHandler

The CommandBus would obviously need to provide a mechanism to correctly parse it.

Some advantages of a command bus

  • Reduced coupling
  • Seamless addition of plugins (when using a decent command bus implementation)
  • Potential reduction of injected dependencies
  • Leads to more cohesive and composable code (many small cohesive command handlers)
  • Theoretically prepares project for different type of communication between layer, e.g. through an enterprise service bus

Some disadvantages of a command bus

  • Complexity overhead (mapping through layers is done in configuration and is less visible)
  • Each command has go through command bus proxy
  • When going for a ready solution of a command bus, you lock yourself to the vendor

Other potential (dis)advantages may come up during discussion of command bus integration into your own project. Whether the approach to use a command bus is fitting for a given project or not depends on many variables and has to be talked through with the system's architect.

OTHER TIPS

You should treat the Command as only a DTO.

public class Command 
{
   public Foo SomeFoo { get;set; }
}

Then we use a visitor pattern on that dto

public interface ICommandHandler<in TCommand>
{
    Task Handle(TCommand command);
}

edit:I got an downvote which I do not understand, its the most clean solution of the answers. And it does not involve type casting and using IsSubclassOf which in it self violate for example Open/closed principle of SOLID. With my solution you work with the IoC not against it. If you need a service just do

public class SendInvoiceCommandHandler : ICommandHandler<SendInvoiceCommand>
{
   private readonly IInvoiceService _invoiceService;

   public SendInvoiceCommandHandler(IInvoiceService invoiceService) 
   {
      _invoiceService = invoiceService;
   }

   public async Task Handle(SendInvoiceCommand cmd)
   {
      await _invoiceService.Send(cmd.InvoiceId);
   }
}

The implementation of ICommandHandler can freely call any service it want and inject it using its constructor.

At runtime I like to use magic to lookup the handlers so I just do

await _cqsClient.ExeceuteAsync(new SendInvoiceCommand(invoiceId));

If you use resharper I have made a plugin that helps when you build a system on visitor pattern like this. https://plugins.jetbrains.com/plugin/12156-resharpervisitorpatternnavigation

It can navigate directly from a instance of the DTO to the handler through a hot key in resharper.

So you need to have a IoC that can register concrete types more dynamic, some have it build in, other dont. I use the vanilla IoC in .NET Core and have written a extension method to the IServiceCollection.

.AddAllTransient(typeof(ICommandHandler<>), typeof(MyCommandThatPointsOutAssembly))

First parameter point out the interface, and the second one a type in assembly you want to want to scan for concrete types of said interface. I wont show that code. But it scans the assembly and registerer all ICommandHandler<T> it can find. I also register a cache for type look up at the same time. This is used from the command runner class like this

public CommandRunner(IServiceProvider serviceProvider, ILogger<CommandRunner> logger, Dictionary<Type, IEnumerable<RegistrationInfo>> typeScanners)
{
    _serviceProvider = serviceProvider;
    _logger = logger;

    _cache = typeScanners[typeof(ICommandHandler<>)]
        .Union(typeScanners[typeof(IQueryHandler<,>)])
        .ToDictionary(info => info.Interface.GetGenericArguments()[0], info => info.Interface);
}

Basicly I build a cache were the DTO is the key, and the value is the concrete type.

Its super easy to execute the Handler once you have that info

private Task ExecuteCommandInternalAsync(Command cmd, IServiceProvider serviceProvider)
{
    var handler = serviceProvider.GetService(_cache[cmd.GetType()]) as dynamic;
    return handler.Handle(cmd as dynamic);
}

edit: You could also lazy build the cache by constructing the ICommandHandler when they are requested someting like

var interface = typeof(ICommandHandler<>).MakeGenericType(cmd.GetType());
var handler = _serviceProvider.GetService(interface) as dynamic;
handler.Handle(cmd as dynamic);      

First, I would recommend to introduce an interface IService to have a common type for all services. Then, extend ICommand by an abstract method SetService(IService), which is implemented in Command<T> like

   void SetService(IService service) {Service = (T)service;}

Assumed the list of services is fixed in your application, one can now implement the service assignment by checking the type one by one, something along the lines of

 void InitServiceForCommand(ICommand cmd)
 {
    Type cmdType = cmd.GetType();
    if(cmd.GetType().IsSubclassOf(typeof(Command<Service1>))
        cmd.SetService(S1);

    if(cmd.GetType().IsSubclassOf(typeof(Command<Service2>))
        cmd.SetService(S2);
    ///...
}

This method now can be called inside the application, after a user initialized the specific command and passed it to the application object.

If you need the list of services to be changeable at run time, you can extend this approach by preparing a Dictionary<Type,IService>, which will hold a mapping from each command type Command<ServiceXYY> to the related service object. This will lead to a solution like this

  Dictionary<Type,IService> serviceMap = ... // some initialization
  // ...
  void InitServiceForCommand(ICommand cmd)
  {
      cmd.SetService(serviceMap(typeof(cmd));
  }
Licensed under: CC-BY-SA with attribution
scroll top