Service Layer
Let's write the business logic to create a new task.
Define the Create Task Method
To paraphrase Uncle Bob, we should write software components to depend on abstractions, not concretions.
We're not just going to create a new class and start to code the create task method. Not yet.
Instead, we first define the create task behaviour in an interface, and then we implement it.
Let's create a new package for our services, com.devtiro.task.service.
Now to define the create task functionality in an interface, let's call
it TaskService:
/** Service for handling Tasks. */
public interface TaskService {
/**
* Creates a new task.
*
* @param request The request object used to create the task.
* @return The created task.
*/
Task createTask(CreateTaskRequest request);
}Note we're using the CreateTaskRequest class we created in the last
lesson as the method's only argument. This means the method has everything it
needs to create a new task.
Also note the method returns a Task entity. This is the task created as
a result of the method's logic.
Note
To decouple this method further, we could return a dedicated object
owned by the service layer, perhaps a CreateTaskResponse object.
We're returning the Task entity to reduce the number of classes we need to
create in an effort to keep the build more approachable.
Now that we've defined the create task method, let's implement it!
Implement the Create Task Method
Although not mandatory, I believe it's useful to separate interface implementations into their own subpackage. This keeps the codebase just a bit more organised.
By convention, this package is often called impl, which is short for
"implementation". It's nested inside the same package as the interfaces.
Let's create our own impl package, com.devtiro.task.service.impl.
Inside this new package we create the class that implements TaskService,
which by convention we'll call TaskServiceImpl:
/** Service for handling Tasks. */
@Service
public class TaskServiceImpl implements TaskService {
/** The task repository. */
private final TaskRepository taskRepository;
/**
* Constructs a new TaskServiceImpl using the provided values.
*
* @param taskRepository The TaskRepository dependency.
*/
public TaskServiceImpl(TaskRepository taskRepository) {
this.taskRepository = taskRepository;
}
@Override
public Task createTask(CreateTaskRequest request) {
// Get the time, date, and timezone right now.
Instant now = Instant.now();
// Create a new Task entity.
Task newTask =
new Task(
null, // Hibernate to generate an ID for us.
request.title(),
request.description(),
request.dueDate(),
TaskStatus.OPEN, // Default to an open status.
request.priority(),
now,
now);
// Save the Task, returning the saved Task to the caller.
return taskRepository.save(newTask);
}
}The @Service annotation is a specialised version of @Component. We
place it on the class to mark it as a bean.
We now have the business logic to create a new task. Let's now move on to the presentation layer.
Summary
- Defined the
TaskServiceinterface. - Defined and implemented the
createTaskmethod.