-
Notifications
You must be signed in to change notification settings - Fork 23
08) Implementing the Service Layer with the Apex Common Library
There is NO FRAMEWORK that can be made for service layer classes. This is a business logic layer and it will differ everywhere. No two businesses are identical. That being said, if you would like to leverage all of the other benefits of the Apex Common Library (primarily Apex Mocks) and you would like your service classes to be able to leverage by the fflib_Application class to allow for dynamic runtime logic generation, you'll need to structure your classes as outlined below. If you don't want to leverage these things, then don't worry about doing what is listed below... but trust me, in the long run it will likely be worth it as your org grows in size.
For every service layer class you create you will create an interface that your service layer implementation class will implement (more on that below). This interface will have every method in your class represented in it. An example of a service interface is below. Some people like to prefix their interfaces with the letter I (example: ICaseService), however I prefer to postfix it with _I or _Interface as it's a bit clearer in my opinion.
This methods in this interface should represent all of the public methods you plan to create for this service class. Private methods should not be represented here.
public interface Task_Service_Interface
{
void createTasks(Set<Id> recordIds, Schema.SObjectType objectType);
}
This class is where things get a little confusing in my opinion, but here's the gist of it. This is the class you will actually call in your apex controllers (or occasionally domain classes) to actually execute the code... however there are no real implementation details in it (that exists in the implementation class outlined below). The reason this class sits in as a kind of middle man is because we want, no matter what business logic is actually called at run time, for our controller classes, batch classes, domain classes, etc to not need to alter the class they call to get the work done. In the Service Factory section below we'll see how that becomes a huge factor. Below is an example of the Service Layer class setup.
//This class is what every calling class will actually call to. For more information on the Application class check out the fflib_Application class
//part of this wiki.
public with sharing class Task_Service
{
//This literally just calls the Task_Service_Impl class's createTasks method
global static void createTasks(Set<Id> recordIds, Schema.SObjectType objectType){
service().createTasks(recordIds, objectType);
}
//This gets an instance of the Task_Service_Impl class from our Application class. This method exists for ease of use in the other methods
//in this class
private static Task_Service_Interface service(){
return (Task_Service_Interface) Application.service.newInstance(Task_Service_Interface.class);
}
}
//Go over how the implementation class is setup and what it is
//Show how using custom metadata you can dynamically swap out business logic at run time.
//Show how the Application class invokes a new instance of the service and how to call the service from a controller