2

I'm looking to implement the command pattern in a web application (asp.net c#)... Since the commands come in text format from the client, what is the best way to translate the string to a command object? Should I use reflection? Currently I just assume the command that comes in matches the file name of a user control. This is a bit of a hack.

Rather than have a select case statement that says if string = "Dashboard" then call Dashboard.Execute(), is there a pattern for working with commands that originate as strings?

asked Apr 4, 2012 at 16:48

3 Answers 3

5

You could use a hash table to map from input strings to Execute methods.

answered Apr 4, 2012 at 16:53
4
  • Bonus points for making it a IDictionary<string, Action> so you don't even need to have methods to call. Commented Apr 4, 2012 at 17:58
  • I think I will use a combination of the two. Using reflection seems a bit goofy although it would prevent me from having to register the commands. I'm not using Unity or an IOC container for this particular application. Commented Apr 4, 2012 at 18:07
  • 1
    Action isn't reflection at all, it is a language feature. Commented Apr 4, 2012 at 19:48
  • I wasn't saying action was reflection. I was talking writing my own TryGetInstance and passing a string. There are various solutions that help you get around having to register all your instances, but I'd rather just register then explicitly using a dictionary. Commented Apr 5, 2012 at 19:52
5

The best way to do this in just about any app is to use an IoC container. Then your command pattern looks something like:

public static class CommandLineActionFactory
{
 public static ICommandLineAction GetAction(string actionName)
 {
 if (actionName == null) throw new ArgumentNullException(nameof(actionName));
 ICommandLineAction ret = ObjectFactory.TryGetInstance<ICommandLineAction>(actionName);
 if (ret == null)
 {
 throw new ArgumentOutOfRangeException(nameof(actionName), $"Action '{actionName}' does not exist.");
 }
 return ret;
 }
}

[code is from a command line app but the pattern works for the web]

The huge advantage here is that you can take advantage of the IoC container to instantiate the handlers, including patching in their dependencies. Also opens the door to stunts like runtime addition of plugins.

answered Apr 4, 2012 at 17:00
3
  • Awesome... Exactly what I need... How do you resolve the action name in trygetinstance... Are you using reflection I'm assuming? I don't see that method in Unity, so I was wondering if this is something you wrote? Commented Apr 4, 2012 at 17:16
  • If i use activator.getinstance, i have to include the assembly name and prepend the namespace to the actionname. This seems a bit goofy. Is this the only way? Commented Apr 4, 2012 at 17:44
  • Sorry, the IoC container in this example is structuremap, not unity nor the activator, which isn't an IoC container. I'll add that the example is a bit dated, you would probably call things in a slightly different way with current versions of structuremap. Commented Apr 4, 2012 at 17:57
0

This is a command pattern written for django 1.4

It can be used the following way:

 p = DesignPattern()
 imps = Implementation.objects.filter(project='Example')
 DesignPatterImplementationsM2MBind(p, imps) 

Django application models.py file:

 class AbstractM2MBindCommand(AbstractCommand):
 """
 Realizes behaviour design pattern `Command'
 """
 model = None
 model_m2m_field = None
 MAX_COMMA_SEPARATED_LENGTH = 1024
 bound_objects = models.CommaSeparatedIntegerField(max_length=MAX_COMMA_SEPARATED_LENGTH, null=True, blank=True, default=None)
 bound_objects_long = models.TextField(null=True, blank=True, default=None)
 class Meta:
 abstract = True
 @classmethod
 def do(cls, model_instance, queryset_to_link):
 #assert isinstance(queryset_to_link, QuerySet)
 setattr(model_instance, cls.model_m2m_field, queryset_to_link)
 ids = [u'%d' % item.pk for item in queryset_to_link]
 model_instance.save()
 fk_field = camel_to_underscore_convert(cls.model.__name__)
 cmd = cls()
 cmd.direction = cls.FORWARD
 joined_ids = u','.join(ids)
 if len(joined_ids) > cls.MAX_COMMA_SEPARATED_LENGTH:
 cmd.bound_objects_long = joined_ids
 cmd.bound_objects = None
 else:
 cmd.bound_objects_long = None
 cmd.bound_objects = u','.join(ids)
 setattr(cmd, fk_field, model_instance)
 cmd.save()
 @classmethod
 def undo(cls, command_id):
 pass
 @classmethod
 def redo(cls, command_id):
 pass 
 class DesignPatterImplementationsBindCommand(AbstractM2MBindCommand):
 model = DesignPattern
 model_m2m_field = 'implementations'
 design_pattern = models.ForeignKey(DesignPattern)
Martijn Pieters
14.7k10 gold badges60 silver badges59 bronze badges
answered Jan 19, 2013 at 22:53

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.