7

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

    ...
}
8
  • 3
    Not sure if I understand this correctly - each of the individual commands are designed for working with a specific service, right? Or in other words, there is no orthogonality between commands and services, right? And you cannot just pass the correct service into a command at construction time since commands are created first, but services later?
    – Doc Brown
    Apr 1, 2020 at 12:11
  • @DocBrown Yes, each command is designed to just call one service method and each service has different methods. So e.g. SubscribeCommand<Service1> would call service1.Subscribe(param1, ...) in it's Execute() method. I do have an instance of the services inside the application when I construct the commands. The Service instances shouldn't be visible outside the application so I could somehow construct the request inside the application if I could pass the command parameter into the application.
    – Martin
    Apr 1, 2020 at 12:48
  • 1
    Do these "services" run in a separate process? Judging by how you phrased your question, it seems the services run concurrently with the user interface. Is this correct? Apr 1, 2020 at 12:50
  • 2
    If the service objects are already there when the commands are constructed, what is the reason for not simply having a constructor parameter in the commands to "inject" the former? public Command1(Service1 service, T1 param1, ...) {Service = service; ...
    – Doc Brown
    Apr 1, 2020 at 16:25
  • 1
    Obligatory all-time classic. Apr 2, 2020 at 18:40

3 Answers 3

6

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.

6
  • Thank you very much for your time and effort to write such a detailed answer! It's a great solution to my problem. I just have some trouble as a programming beginner to implement your Command Bus in C# without using java's generic map. Any ideas of how I solve this?
    – Martin
    Apr 3, 2020 at 13:30
  • @Martin I unfortunately do not know. I haven't really programmed in C#. Perhaps the best is to look for some already existing implementation of a service bus.
    – Andy
    Apr 4, 2020 at 17:31
  • @Andy thank you very much for the write up. I've been implementing something fairly similar in Python, the way I understand the UserService becomes a command handler itself? In our current project, we wrote them in two different layers (the message bus receiving the Command from a dispatcher, and sending it to the appropriate CommandHandler, that in turn would call a Service). I'm guessing this is mostly similar? It's not clear to me how to inject repositories though (for example, our CommandHandler needs two repositories and a couple of factories - apart from the command itself). May 25, 2022 at 3:28
  • 1
    @lowercase00, for simplicity reasons, I indeed stated an example with the UserService being a command handler, in reality RegisterUserCommand would likely be handled by RegisterUserCommandHandler (RUCH for short). I am not familiar with Python but in Java, the repositories would be injected into the RUCH through a constructor by defining them as dependencies via application framework (such as Spring for Java, or Symfony for PHP). Quick Google search gives me "Dependency Injector" framework for Python, have a look at that.
    – Andy
    May 25, 2022 at 6:15
  • 1
    @lowercase00, about your separation of concerns, if you services are domain services and not application services, it is completely fine. However your command handlers should replace you application services completely. So if your services are not domain-based, you are introduced unnecessary layering. When implemented, command handlers go hand in hand with domain driven design, where they forward execution to entities and domain services, making them (the command handlers) basically a mechanism to forward a system intent to appropriate domain objects.
    – Andy
    May 25, 2022 at 6:20
2

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);      
7
  • I am not sure if I got your idea. So you're saying the user should instantiate a concrete command and pass it to a <TCommand> Template function inside the application and the application should then create the correct Command handler with the correct service and execute the handle command method?
    – Martin
    Apr 2, 2020 at 11:49
  • How the command is created is irrelevant actually, in my systems we both create from within the application (commandhandlers create and queue other commands) . But we also receive commands over Rest. What's important is to separate data and the actual execution.
    – Anders
    Apr 2, 2020 at 14:32
  • I updated my asnwer after a downvote, hope its easier to understand
    – Anders
    Apr 3, 2020 at 9:16
  • Thank you for your great help. Your answer suggests the right approach by splitting the command handler and the command parameter. But to implement this approach I need some sort of command-handler-mapping just like @Andy proposed with the Command Bus. Do you have any idea how I could do this in C#, better than I did in my updated question?
    – Martin
    Apr 3, 2020 at 13:24
  • You can do it pretty easy depending on your IoC, in vanilla .NET Core you need handle alot yourself. You need to build a cache of commands to handler lookup. And inject that concrete type and execute the Handle method basicly. I can update my answer with some pseudo code for it
    – Anders
    Apr 3, 2020 at 14:20
0

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));
  }
2
  • I actually thought about a similar solution to use Method Injection and map the services with a service map, just like you suggested. The problem is, that Method Injection is not a clean solution here because the service is not an optional parameter, but rather a necessary one.
    – Martin
    Apr 3, 2020 at 13:18
  • @Martin: if you see that really as a problem, I think you need to combine the service map with a command factory and prohibit direct instantiation of commands without that factory. The factory then could hold the service map and pass the correct service during construction of the command. But beware, you may easily add more complexity than really required, and this has a certain potential to become overengineered. Sometimes the "cleanest" solution is the simpler one, even if it contains some trade-off.
    – Doc Brown
    Apr 3, 2020 at 16:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.