I'm currently experimenting with some architectural patterns, one of them being the implementation of CQRS, especially the "Command" part of the pattern.
Basically I have commands like
public class SavePersonCommand {
@Inject
private IPersonRepository repository;
Person person;
public SavePersonCommand(Person personToSave){
this.person = personToSave;
}
public void execute(){
...
repository.save(personToSave);
...
}
}
For simplicity I don't specify any interfaces/abstract classes the command might implement. The point is, this is the standard implementation of a Command, you pass all the necessary information to the constructor and then you have a parameterless method (i.e. execute()
) which executes the business logic of your command.
The issue though is IPersonRepository
. IPersonRepository
contains the logic for persisting the entity to some storage and thus belongs to the data layer of my application. Btw, the simplified structure of my app is like this
ApiLayer -> Core <- DAL
where ApiLayer depend on Core and DAL depends on Core. Meaning Core does not have dependencies on the specific DAL nor does it obviously have on the Api layer. So the distribution of the classes would be..
ApiLayer
PersonApi
Core
IPersonRepository
PersonCommand
Person
DAL
PersonRepository -> IPersonRepository
Now, in the ApiLayer, where I want would normally get an instance of the SavePersonCommand
.
@Path("/api/v1/person")
public class PersonApi {
@POST
public void savePerson(Person person) {
SavePersonCommand personCommand = new SavePersonCommand(person);
personCommand.execute();
}
}
The issue here is however, how do I get the IPersonRepository
injected into the command. I wouldn't want to get it injected in the ApiLayer
like
@Path("/api/v1/person")
public class PersonApi {
@Inject
private IPersonRespository personRepo;
@POST
public void savePerson(Person person) {
// obviously modify the interface of SavePersonCommand
SavePersonCommand personCommand = new SavePersonCommand(personRepo, person);
...
}
}
..this is kinda ugly..
I have some thoughts but would like to hear how you implement this normally.
Based on Steven's hints the simplest approach to solve my issue is the following.
Here I have the following
public class SavePersonCommandHandler implements ICommandHandler<SavePersonCommand> {
@Inject
IPersonRepository personRepository;
@Override
public void handle(SavePersonCommand command) {
Person person = command.getPerson();
personRepository.save(person);
}
}
The SavePersonCommand
is simply a data object that transfers the data from my Api layer to the Core layer.
public class SavePersonCommand {
private Person person;
public SavePersonCommand(Person person) {
this.person = person;
}
public Person getPerson() {
return this.person;
}
}
I could even only pass the person's properties as native data types rather than passing the entire Person
object. Thus, I could remove the dependency to the datatype which I might want to only use in my core layer.
The api layer then gets an instance of the required command handler.
@Path("/api/v1/person")
public class PersonApi {
@Inject
ICommandHandler<SavePersonCommand> commandHandler;
@POST
public void savePerson(Person person) {
commandHandler.handle(new SavePersonCommand(person));
}
}
Note that normally you also add a Bus in between that "sends" a command down the pipe which then gets intercepted by the correct CommandHandler. Didn't want to complicate as for the sake of my question this is the answer I found.
These articles were quite helpful: