Domain Layer - cdelfattore/apex-enterprise-patterns GitHub Wiki
The Domain layer is a class that represents a standard or custom object. It contains methods that perform actions on the records that belong to the instance of the class.
Use the plural form of the object name (Accounts, Contacts, Opportunities, etc.) for the class name.
Accounts
Contacts
Opportunities
When retrieving records from the domain prefix get
to the method name. When setting field values prefix set
to the method name. Additional methods, such as ones that calculate or find the minimum or maximum can also be added to the domain class.
getAccountNames
setContactRecordTypeIds(Id recordTypeId)
calculateOpportunityScore()
There are two virtual classes that need to be extended when creating a domain class. The fflib_SObjects class needs to be extended in the apex class and the fflib_ISObject interface needs to be extended in the interface class for the domain class. The below example will go into more detail. More information about the virtual class and virtual interface can be found below:
fflib_SObjects, fflib_ISObject
To create an instance of a domain class. Create and call static newInstance methods. I have always called a domain instance variable [objectPluralName]Domain.
IAccounts accountsDomain = Accounts.newInstance(AccountsSelector.newInstance().selectById(accountsId));
The above method uses a selector method to create an account domain instance. This selector method returns a list of accounts. You can also create a new instance method that uses a set of account ids to create a domain.
See below for a full example of a domain class.
/**
* @description Domain class for the Account object.
* @author cdelfattore
* @since 2024-05-20
* @group Domain
*/
public class Accounts extends fflib_SObjects
implements IAccounts
{
/**
* @description Use this method to create a instance of the Accounts class.
* @param recordList
* @return `IAccounts`
*/
public static IAccounts newInstance(List<Account> recordList)
{
return (IAccounts) Application.Domain.newInstance(recordList);
}
/**
* @description Constructor for this domain class.
* @param sObjectList
*/
public Accounts(List<Account> sObjectList)
{
super(sObjectList, Schema.Account.SObjectType);
}
/**
* @description Use the getRecords method from the fflib_SObjectDomain class to retrieve the Account records that are a part of this domain.
* @return `List<Account>`
*/
public List<Account> getAccounts()
{
return (List<Account>) getRecords();
}
/**
* @description This could normally be done with a roll up summary field. For the sake of an example we will use it.
*/
public void setContactCount()
{
for (Account account : getAccounts())
{
if (account.Contacts != null)
{
account.Contact_Count__c = account.Contacts.size();
}
else
{
account.Contact_Count__c = 0;
}
}
}
/**
* @description Set the description of all the accounts in the domain.
* @param description
*/
public void setDescription(String description)
{
for (Account account : getAccounts())
{
account.Description = description;
}
}
/**
* @description Constructor class
*/
public class Constructor implements fflib_IDomainConstructor
{
public fflib_SObjects construct(List<Object> objectList)
{
return new Accounts((List<SObject>) objectList);
}
}
}
The above class will be update periodically, the most up to date version can be found [here](https://github.com/cdelfattore/apex-enterprise-patterns/blob/master/force-app/main/default/classes/Accounts.cls).
Interface for the above domain class. Be sure to include all methods in this interface that you would like to be able to reference in other apex classes (service classes).
/**
* @description Interface for the Accounts Domain.
* @author cdelfattore
* @since 2024-05-22
* @group Domain
*/
public interface IAccounts extends fflib_ISObjects
{
List<Account> getAccounts();
void setContactCount();
void setDescription(String description);
}
The above interface will be update periodically, the most up to date version can be found here.
For some domain classes, it is best to represent the object using a singleton instance of the class. RecordType for example. Singleton instance will only ever have one instance in the context of the running process. There is no need to have multiple versions of the class created.
Additional examples can be found is this repo and at Apex Enterprise Pattern Github repositories.