Skip to content

08) Implementing the Service Layer with the Apex Common Library

Coding With The Force edited this page Apr 9, 2021 · 12 revisions

Implementing the Service Layer with the Apex Common Library

Preparation for the rest of this article

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.


The Service Interface

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);
}

The Service Layer Class

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);
	}
}

The Service Implementation Class

//Go over how the implementation class is setup and what it is


The fflib_Application.ServiceFactory class

//Show how using custom metadata you can dynamically swap out business logic at run time.


Tying all the classes together

//Show how the Application class invokes a new instance of the service and how to call the service from a controller


Next Section

Part 9: The Template Method Pattern

Clone this wiki locally