Created
February 13, 2019 21:26
-
-
Save lars-erik/d3359a6d0425a8b30dfe4e853733a411 to your computer and use it in GitHub Desktop.
Simple but flexible command handling
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using NUnit.Framework; | |
namespace SimpleCommands.Tests | |
{ | |
[TestFixture] | |
public class When_Processing_A_Command_With_A_Composite | |
{ | |
[Test] | |
public void The_Outer_One_Aggregates_Results() | |
{ | |
var command = new SpecificCommand("Some data"); | |
var handler = new CompositeHandler<SpecificCommand>( | |
new EchoTask(), | |
new EchoTask() | |
); | |
var result = handler.Execute(command); | |
Assert.That(result, | |
Is.InstanceOf<AggregateCommandResult>() & | |
Has.Property("Results").With.Exactly(2).With.Property("Data").EqualTo("Some data echoed") | |
); | |
} | |
[Test] | |
public void The_Composite_Can_Log_Exceptions_And_Cancel_Processing() | |
{ | |
var command = new SpecificCommand("Some data"); | |
var handler = new CompositeHandler<SpecificCommand>( | |
new EchoTask(), | |
new ErrorTask(), | |
new EchoTask() | |
); | |
var result = handler.Execute(command); | |
Assert.That(result, | |
Is.InstanceOf<AggregateCommandResult>() & | |
Has.Property("Results").With.One.InstanceOf<EchoResult>().With.Property("Data").EqualTo("Some data echoed") & | |
Has.Property("Results").With.One.InstanceOf<ErrorResult>() | |
); | |
} | |
} | |
public class SpecificCommand : Command | |
{ | |
public string Data { get; set; } | |
public SpecificCommand() | |
{ | |
} | |
public SpecificCommand(string data) | |
{ | |
Data = data; | |
} | |
} | |
public class EchoTask : CommandHandler<SpecificCommand> | |
{ | |
public override CommandResult Execute(SpecificCommand command) | |
{ | |
return new EchoResult(command.Data + " echoed"); | |
} | |
} | |
public class ErrorTask : CommandHandler<SpecificCommand> | |
{ | |
public override CommandResult Execute(SpecificCommand command) | |
{ | |
throw new NotImplementedException(); | |
} | |
} | |
public class EchoResult : CommandResult | |
{ | |
public string Data { get; } | |
public EchoResult(string data) | |
{ | |
Data = data; | |
} | |
} | |
public class CompositeHandler<T> : CommandHandler<T> | |
where T : Command | |
{ | |
private readonly List<ICommandHandler<T>> handlers; | |
public CompositeHandler(params ICommandHandler<T>[] handlers) | |
{ | |
this.handlers = handlers.ToList(); | |
} | |
public override CommandResult Execute(T command) | |
{ | |
return handlers.Aggregate( | |
new AggregateCommandResult(), | |
(r, h) => Execute(command, r, h) | |
); | |
} | |
private static AggregateCommandResult Execute(T command, AggregateCommandResult result, ICommandHandler<T> handler) | |
{ | |
if (result.Results.OfType<ErrorResult>().Any()) | |
return result; | |
return result.Add(TryExecute(command, handler)); | |
} | |
private static CommandResult TryExecute(T command, ICommandHandler<T> handler) | |
{ | |
CommandResult commandResult; | |
try | |
{ | |
commandResult = handler.Execute(command); | |
} | |
catch | |
{ | |
commandResult = new ErrorResult(); | |
} | |
return commandResult; | |
} | |
} | |
public class AggregateCommandResult : CommandResult | |
{ | |
private readonly List<CommandResult> results = new List<CommandResult>(); | |
public IEnumerable<CommandResult> Results => results; | |
public AggregateCommandResult Add(CommandResult result) | |
{ | |
results.Add(result); | |
return this; | |
} | |
} | |
public abstract class CommandHandler<T> : ICommandHandler<T> | |
where T : Command | |
{ | |
public CommandResult Execute(Command command) | |
{ | |
return Execute((T) command); | |
} | |
public abstract CommandResult Execute(T command); | |
} | |
public interface ICommandHandler<T> : ICommandHandler | |
where T : Command | |
{ | |
CommandResult Execute(T command); | |
} | |
public interface ICommandHandler | |
{ | |
CommandResult Execute(Command command); | |
} | |
public class Command | |
{ | |
} | |
public class CommandResult | |
{ | |
} | |
public class ErrorResult : CommandResult | |
{ | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment