Steven van Deursen
AKA .NET Junkie
Where?
Asking a question should not change the answer.
Bertrand Meyer
Meyer, Bertrand. "Eiffel: a language for software engineering" (PDF). p. 22. Retrieved 16 December 2014.
Bertrand Meyer first introduced the idea as a part of of his work on the Eiffel programming language.
https://en.wikipedia.org/wiki/Command–query_separation
What?
Just show me the code Aaron.
Just show me the code Aaron.
var command = new ChangeChannel
{
ChannelId = channelId
};
public class ChangeChannelCommandHandler
{
private readonly TV _tv;
public ChangeChannelCommandHandler(TV tv)
{
_tv = tv;
}
public void Handle(ChangeChannelCommand command)
{
// Change the Channel
}
}
Just show me the code Aaron.
public class TvController
{
private readonly ChangeChannelCommandHandler handler;
public TvController(ChangeChannelCommandHandler handler)
{
this.handler = handler;
}
public void ChangeChannel(int channelId)
{
var command = new ChangeChannelCommand
{
ChannelId = channelId,
};
this.handler.Handle(command);
}
}
Just show me the code Aaron.
var query = new GetChannelQuery();
public class GetChannelQueryHandler
{
private readonly TV _tv;
public GetChannelQueryHandler(TV tv)
{
_tv = tv;
}
public int Handle(GetChannelQuery query)
{
return _tv.Channel;
}
}
Just show me the code Aaron.
public class TvController
{
private readonly ChangeChannelCommandHandler _changeChannelCommandHandler;
private readonly GetChannelQueryHandler _getChannelQueryHandler;
public TvController(
MoveCustomerCommandHandler changeChannelCommandHandler,
GetChannelQueryHandler getChannelQueryHandler)
{
_changeChannelCommandHandler = changeChannelCommandHandler;
_getChannelQueryHandler = getChannelQueryHandler;
}
public void ChangeChannel(int channelId)
{
...
}
public int GetChannel()
{
var query = new GetChannelQuery();
return _getChannelQueryHandler.Handle(query);
}
}
So what Aaron, why should I care about this pattern?
Single Responsibility
So what Aaron, why should I care about this pattern?
Boundaries that you can decorate
So what Aaron, why should I care about this pattern?
Boundaries in an application give you and opportunity to add cross cutting concerns or targeted aspects to your logic
We can do this in CQRS by created interfaces for the command and query handlers, and use the decorator structural pattern.
public interface ICommandHandler<TCommand>
{
void Handle(TCommand command);
}
So what Aaron, why should I care about this pattern?
public class ChangeChannelCommandHandler : ICommandHandler<ChangeChannelCommand>
{
private readonly TV _tv;
public ChangeChannelCommandHandler(TV tv)
{
_tv = tv;
}
public void Handle(ChangeChannelCommand command)
{
// Change the Channel
}
}
Just show me the code Aaron.
public class TvController
{
private readonly ICommandHandler<ChangeChannelCommand> _handler;
public TvController(ICommandHandler<ChangeChannelCommand> handler)
{
_handler = handler;
}
public void ChangeChannel(int channelId)
{
var command = new ChangeChannelCommand
{
ChannelId = channelId,
};
_handler.Handle(command);
}
public void GetChannel()
{
...
}
}
Just show me the code Aaron.
public class LivingRoom
{
private const int ABCKidsChannel = 24;
private readonly TvController _tvController;
public LivingRoom(TvController tvController)
{
_tvController = tvController;
}
public void EnterRoom()
{
if(_tvController.GetChannel() != ABCKidsChannel)
{
//Chnage the channel to ABC Kids
_tvController.ChangeChannel(ABCKidsChannel);
}
}
}
Just show me the code Aaron.
public class House
{
public LivingRoom LivingRoom;
public void LivingRoom()
{
var tv = new TV();
var changeChannelCommandHandler = new ChangeChannelCommandHandler(tv);
var tvController = new TvController(changeChannelCommandHandler);
LivingRoom = new LivingRoom(tvController);
LivingRoom.EnterRoom();
}
}
Just show me the code Aaron.
public class GuardFromChannelNineDecorator : ICommandHandler<ChangeChannelCommand>
{
private const int NineEntertainment Channel = 9;
private readonly ICommandHandler<TCommand> _decoratee
private readonly TV _tv;
public ChangeChannelCommandHandler(TV tv, ICommandHandler<ChangeChannelCommand> decoratee)
{
_tv = tv;
_decoratee = decoratee;
}
public void Handle(ChangeChannelCommand command)
{
if(command.ChannelId == NineEntertainment)
{
throw new System.InvalidOperationException("You can not watch Married at First Sight");
}
decoratee.Handle(command);
}
}
public class GuardFromChannelNineDecorator : ICommandHandler<ChangeChannelCommand>
{
private const int NineEntertainment Channel = 9;
private const int ABCKidsChannel = 24;
private readonly ICommandHandler<TCommand> _decoratee
private readonly TV _tv;
public ChangeChannelCommandHandler(TV tv, ICommandHandler<ChangeChannelCommand> decoratee)
{
_tv = tv;
_decoratee = decoratee;
}
public void Handle(ChangeChannelCommand command)
{
if(command.ChannelId == NineEntertainment)
{
command.ChannelId = ABCKidsChannel;
}
decoratee.Handle(command);
}
}
Just show me the code Aaron.
public class House
{
public LivingRoom LivingRoom;
public void LivingRoom()
{
var tv = new TV();
var changeChannelCommandHandler = new ChangeChannelCommandHandler(tv);
var guardFromChannelNineDecorator =
new GuardFromChannelNineDecorator(tv, changeChannelCommandHandler);
var tvController = new TvController(guardFromChannelNineDecorator);
LivingRoom = new LivingRoom(tvController);
LivingRoom.EnterRoom();
}
}
Just show me the code Aaron.
Just show me the code Aaron.
public class House
{
public LivingRoom LivingRoom;
public void LivingRoom()
{
var tv = new TV();
var changeChannelCommandHandler = new ChangeChannelCommandHandler(tv);
var turnTvOffAfterFiveAttemptsDecorator =
new TurnTvOffAfterFiveAttemptsDecorator(tv, changeChannelCommandHandler);
var guardFromChannelNineDecorator =
new GuardFromChannelNineDecorator(tv, turnTvOffAfterFiveAttemptsDecorator);
var tvController = new TvController(guardFromChannelNineDecorator);
LivingRoom = new LivingRoom(tvController);
LivingRoom.EnterRoom();
}
}
Just show me the code Aaron.
var container = new Container();
container.Register(
typeof(ICommandHandler<ChangeChannelCommand>),
typeof(ChangeChannelCommandHandler));
container.RegisterDecorator(
typeof(ICommandHandler<ChangeChannelCommand>),
typeof(TurnTvOffAfterFiveAttemptsDecorator));
container.RegisterDecorator(
typeof(ICommandHandler<ChangeChannelCommand>),
typeof(GuardFromChannelNineDecorator));
Note not all DI libraries are created equally, some may not support syntax like this.
Cross-Cutting Concerns
In aspect-oriented software development, cross-cutting concerns are aspects of a program that affect other concerns.
https://en.wikipedia.org/wiki/Cross-cutting_concern
Link to my Blog