I know that there are a lot of people out there who think design patterns are not useful or not important. You can learn them from any book or catalogue and then you simply add them to you code. While I try to be respectful of all opinions and definitely not trying to start a debate, this is so not true. To really understand how a pattern works and then combine them in a meaningful way takes a lot of practice, experience and a deep understanding of the underlying concepts. I have shown how decorators can be combined with the object and class adapters in a really tricky situation to make use of both of their advantages when decorating seems impossible. And now, I will show you how decorators can be used with another commonly used design pattern: command.

Basic command implementation

So for a basic command implementation you need a command interface, like this:

public interface ICommand
{
  void Execute();
}

Then you implement this interface for all operations you want to perform (or simply use a 'delegate-command' of some sort, if you are lazy) and then create an invoker component that simply calls the command:

public class Invoker
{
  public void Invoke(ICommand c)
  {
    c.Execute();
  }
}

This is just a basic invoker implementation. Of course, the whole point of applying the command pattern is to 'objectify your method calls' and pass them to the invoker that can add extra functionality around them. So you can have a performance-measuring invoker:

public class Invoker
{
  private readonly Action<long> log;
  public class Invoker(Action<long> log)
  {
    this.log = log;
  }
  
  public void Invoke(ICommand c)
  {
    var sw = Stopwatch.StartNew();
    c.Execute();    
    long elapsed = sw.ElapsedMilliseconds;
    log(elapsed);
  }
}

Or you can have a simple logging invoker:

public class Invoker
{
  private readonly Action<string> log;
  public class Invoker(Action<string> log)
  {
    this.log = log;
  }
  
  public void Invoke(ICommand c)
  {
    var correlationId = Guid.NewGuid();
    log($"{correlationId}: Executing command of type {c}");
    try
    {    
      c.Execute();        
      log($"{correlationId}: Execution successful");
    }
    catch (Exception ex)
    {
	  log($"{correlationId}: Execution failed: {ex}");
    }    
  }
}

Of course these are just some very basic examples, but you can imagine how the invoker can be improved with all kinds of execution logic.
But how can you compose these invokers? And bette yet, how can you configure what invoker (or better yet, invokers) to use in the system?
Maybe you want to use the performance measuring invoker when developing to measure performance, but the logger invoker is not needed (after all,
you have a debugger). And then, when you switch to your production system, you want to change to the logging invoker (since there is no debugger), but
by that time, the performance-measuring invoker is not required.

Decorator to the rescue

Whenever the requirement of composing different aspects of the same component comes up, or whenever you have to add additional responsibilities dynamically
to a service in your system, the decorator design pattern is a very good choice. I always tell my students that if you only learn one, this should be it.
So how can decorator help our scenario? Well, first, you have to define an interface for the invoker:

public interface IInvoker
{
  void Invoke(ICommand command);
}

And then, implement a base-case:

public interface BasicInvoker : IInvoker
{
  public void Invoke(ICommand command)
  {
    command.Execute();
  }
}

And then, implement the other invokers as decorators for the interface:

public class PerformanceMonitoringInvoker : IInvoker
{
  private readonly Action<long> log;
  private readonly IInvoker decoratee;
  public class PerformanceMonitoringInvoker(Action<long> log, IInvoker decoratee)
  {
    this.log = log ?? throw new ArgumentNullException(nameof(log));
	this.decoratee = decoratee ?? throw new ArgumentNullException(nameof(decoratee));
  }
  
  public void Invoke(ICommand c)
  {
    var sw = Stopwatch.StartNew();
    decoratee.Invoke(c);
    long elapsed = sw.ElapsedMilliseconds;
    log(elapsed);
  }
}

public class LoggingInvoker : IInvoker
{
  private readonly Action<string> log;
  private readonly IInvoker decoratee;
  public class LoggingInvoker(Action<string> log)
  {
    this.log = log ?? throw new ArgumentNullException(nameof(log));
	this.decoratee = decoratee ?? throw new ArgumentNullException(nameof(decoratee));
  }
  
  public void Invoke(ICommand c)
  {
    var correlationId = Guid.NewGuid();
    log($"{correlationId}: Executing command of type {c}");
    try
    {    
      decoratee.Invoke(c);
      log($"{correlationId}: Execution successful");
    }
    catch (Exception ex)
    {
	  log($"{correlationId}: Execution failed: {ex}");
    }    
  }
}

And then, whereever the invoker is needed you can inject the IInvoker interface. And that IInvoker instance can be anything. You can have a basic invoker:

IInvoker invoker = new BasicInvoker();

Or, you can have one that measures performance:

IInvoker invoker = new PerformanceMonitoringInvoker(Console.WriteLine,new BasicInvoker());

Or one that logs everything:

IInvoker invoker = new LoggingInvoker(Console.WriteLine,new BasicInvoker());

Or both at the same time — without having to write extra code or modify the implementation of existing invokers:

Or, you can have one that measures performance:

IInvoker invoker = new LoggingInvoker(Console.WriteLine, new PerformanceMonitoringInvoker(Console.WriteLine,new BasicInvoker()));

And now you can configure your DI container to inject whichever version you need (or you can even use the auto-decorator feature of Autofac).

Design patterns medley: Command and decorator
Share this

© 2019. All Rights Reserved.

Falconium theme based on Ghostium Theme

Proudly published with Ghost