Apex Design Patterns are reusable solutions to common problems that developers face while working on the Salesforce platform. These patterns help in designing and implementing scalable, maintainable, and robust applications. We’ll discuss the following basic patterns:
- Singleton Pattern
- Selector Pattern
- Domain Pattern
- Service Pattern
- Singleton Pattern
The Singleton pattern ensures that only one instance of a class exists throughout the application’s lifecycle. This pattern is useful for managing resources that should be shared across the application.
Example:
public class SingletonExample { private static SingletonExample instance; private SingletonExample() { } public static SingletonExample getInstance() { if (instance == null) { instance = new SingletonExample(); } return instance; } }
Usage:
SingletonExample singleton = SingletonExample.getInstance();
- Selector Pattern
The Selector pattern is used to encapsulate SOQL queries in separate classes, making it easier to maintain and test queries. By using this pattern, you can abstract complex queries and reuse them across your application.
Example:
public class AccountSelector { public List<Account> selectActiveAccounts() { return [ SELECT Id, Name, Industry, AnnualRevenue FROM Account WHERE IsActive__c = true ]; } }
Usage:
AccountSelector selector = new AccountSelector(); List<Account> activeAccounts = selector.selectActiveAccounts();
- Domain Pattern
The Domain pattern encapsulates all business logic related to a particular object (e.g., Account, Opportunity) in a single class. This pattern helps in enforcing object-level validation, default values, and complex calculations.
Example:
public class AccountDomain { private List<Account> accounts; public AccountDomain(List<Account> accounts) { this.accounts = accounts; } public void applyDiscount(Decimal discountPercentage) { for (Account account : accounts) { account.AnnualRevenue = account.AnnualRevenue * (1 - discountPercentage / 100); } } }
Usage:
List<Account> accounts = [SELECT Id, AnnualRevenue FROM Account]; AccountDomain domain = new AccountDomain(accounts); domain.applyDiscount(10); update accounts;
- Service Pattern
The Service pattern is used to encapsulate business logic that spans multiple objects. It helps in centralizing the logic, making it reusable and maintainable.
Example:
public class OpportunityService { public static void updateAccountRevenue(List<Opportunity> opportunities) { Map<Id, Account> accounts = new Map<Id, Account>(); for (Opportunity opp : opportunities) { if (!accounts.containsKey(opp.AccountId)) { accounts.put(opp.AccountId, new Account(Id = opp.AccountId, AnnualRevenue = 0)); } accounts.get(opp.AccountId).AnnualRevenue += opp.Amount; } update accounts.values(); } }
Usage:
List<Opportunity> opportunities = [SELECT Id, AccountId, Amount FROM Opportunity]; OpportunityService.updateAccountRevenue(opportunities);
This tutorial covered four essential Apex Design Patterns: Singleton, Selector, Domain, and Service. There are other patterns also and we will cover them later however these patterns help in building scalable, maintainable, and robust applications on the Salesforce platform. By incorporating these patterns, you can improve the structure and organization of your code, making it easier to understand and maintain. For additional information please see: Commonly used design patterns in Salesforce Apex – Salesforce Watch
Service Oriented Architecture in Salesforce Development
Factory Method Pattern and Reflection in Apex within Salesforce: An In-Depth Analysis with Examples