Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to share the same context between commands in Command-Pattern with C#?

I've implemented the command pattern (in a multi-support way) in my application.

Structure:

class MultiCommand : BaseCommand

abstract class BaseCommand : ICommand

Process Flow:

   var commandsGroup = new MultiCommand(new List<ICommand>()
            {
                new Command1(),
                new Command2(),
                new Command3(),
            });

   commandsGroup.Execute()

Now, suppose that in Command1 a somethingID is changed and I'll use this new value in Command2... And also, that there are plenty of other properties and objects that are being affected during the whole execution process.

Also, there are some interface implementations that should be available at any command just using the context object like:

Context.ServerController.something();

The instantiation of the IServerController will take place just before the multiCommandGroup initialization.

How can I have a shared context like this for all Commands of the group?

Example of the Context class:

public class CommandContext
{
    public IServerController ServerController;
    public RequiredData Data { get; set; }

    public CommandContext(){}
}

IMPORTANT A minimal implementation Code is here

like image 938
Giannis Grivas Avatar asked Jun 17 '16 14:06

Giannis Grivas


People also ask

What is the command pattern and why is it important?

The command pattern helps us do that. Definition: The command pattern encapsulates a request as an object, thereby letting us parameterize other objects with different requests, queue or log requests, and support undoable operations. The definition is a bit confusing at first but let’s step through it.

What is the difference between remote control and command pattern?

In analogy to our problem above remote control is the client and stereo, lights etc. are the receivers. In command pattern there is a Command object that encapsulates a request by binding together a set of actions on a specific receiver. It does so by exposing just one method execute () that causes some actions to be invoked on the receiver.

How do I share state between multiple components in a tree?

By using Context we are sharing state between multiple components without explicitly passing a prop through every level of the tree. This example app here shows a recipe that you can use to keep such shared state in your application. In a nutshell, we are doing the following: We wrap the components within the Provider of this UsersContext.

What is context and how do I use it?

By using Context we are sharing state between multiple components without explicitly passing a prop through every level of the tree. This example app here shows a recipe that you can use to keep such shared state in your application. In a nutshell, we are doing the following:


2 Answers

1) If you want to keep this interface, then you have to pass this context as constructor parameter:

new MultiCommand(new List<ICommand>()
            {
                new Command1(context),
                new Command2(context),
                new Command3(context),
            })

2) As another option you can accept list of delegates instead of list of commands. MultiCommand will be look like this:

class MultiCommand : ICommand
{
    public MultiCommand(List<Func<Context, Command>> commands, Context context)

}

That is almost the same except MultiCommand is responsible for all the commands share the same context.

3) Looks like commands in MultiCommand depends on result of previous command. In this case Command pattern is not probably the best. Maybe you should try to implement Middleware chain here?

interface IMiddleware<TContext>
{
   void Run(TContext context);
}

class Chain<TContext>
{
    private List<IMiddleware<TContext>> handlers;

    void Register(IMiddleware<TContext> m);

    public void Run(TContext context)
    {
        handlers.ForEach(h => h.Run(context));
    }
}
like image 99
Valentin Korolev Avatar answered Oct 17 '22 08:10

Valentin Korolev


I would suggest to make somethings generic. Here is a super simple example.

class MultiCommand<TContext>  
{
    List<Command<TContext>> Commands;
    TContext Context;
}
like image 37
Daniel A. White Avatar answered Oct 17 '22 06:10

Daniel A. White