- Overview
- View layer
- Application logic layer(this post)
- Service - Application State layer
The Command
A command is a stateless object which is executed once and then disposed of. It has a single responsibility, which clearly defines its purpose.Such a command can for example have the responsibility to create a new contact, calculate the total amount of money a client has to pay etc.
This leads to a higher number of classes, but it has some advantages over a controller:
- A command will have less dependencies because of its single responsibility. This makes it easier to test.
- When using good class/package name conventions it's easier to find a certain piece of logic.
Running it in the background
Because business logic should run in a background thread to avoid blocking the UI, I'm using a convention to make every command extend from the JavaFx Service class.The Service class is used in JavaFx to run some code in one or more background threads. More info on this class can be found here: http://docs.oracle.com/javafx/2/api/javafx/concurrent/Service.html
This fits perfectly in my design because it makes sure that all business logic is executed in a background thread. Because it's an integral part of our application structure developers won't forget to start a new thread because it will be done transparently when creating a new instance of a command and starting it.
How it looks like in code
This is how it looks like in code. The command has one parameter which should be set before starting the command and it has a dependency to the IEventService. When it's finished it return an EventVO instance with all the details of the event.public class LoadEventDetailsCommand extends Service<EventVO> { @Inject public IEventService eventService; public String eventId; @Override protected Task<EventVO> createTask() { return new Task<EventVO>() { @Override protected EventVO call() throws Exception { return eventService.getEventDetails(eventId); } }; } }
And this is how you can use it in the mediator. The commandProvider is something which I'll discuss in a moment, but it basically creates a new instance of a certain command class. When you call the start() method the command will start its execution in a background thread.
LoadEventDetailsCommand command = commandProvider.get(LoadEventDetailsCommand.class); command.setOnSucceeded(new LoadEventDetailsSucceededHandler()); command.eventId = eventSelectionModel.getSelectedEvent().getId(); command.start();
And finally the succeeded handler which is just an inner class in my mediator. It gets the EventVO result from the command and asks the view to show the new details:
private class LoadEventDetailsSucceededHandler implements EventHandler<WorkerStateEvent> { @Override public void handle(WorkerStateEvent workerStateEvent) { view.updateEventDetails((EventVO) workerStateEvent.getSource().getValue()); } }
The CommandProvider
The CommandProvider is a class which I've created as sort of a Command factory, which uses a Guice injector to produce the instances. This allows us to inject dependencies in the commands.The interface:
public interface ICommandProvider { <T extends Service> T get(Class<T> type); }
And the implementation:
public class CommandProvider implements ICommandProvider { @Inject public Injector injector; public <T extends Service> T get(Class<T> type) { return injector.getInstance(type); } }
I enjoy reading your posts. Thank you for taking the time to offer this useful information. This fantastic item will undoubtedly be included to my article area.
ReplyDeleteRead More: OTM Training