Design Patterns in Salesforce: Deep Dive into Singleton and Factory

Design Patterns in Salesforce: Deep Dive into Singleton and Factory

When developing applications in Salesforce, developers often face challenges such as:

  • Avoiding repeated SOQL queries and redundant object creation

  • Maintaining clean, reusable, and scalable code

  • Supporting multiple implementations (e.g., Email, SMS, Push notifications) without breaking existing logic

This is where design patterns come in.

Design patterns are standard, reusable solutions to common software design problems. They don’t provide code directly but give you a proven approach to structure your logic.

In this blog, we’ll dive deep into two popular design patterns in Salesforce Apex:

  • Singleton Pattern

  • Factory Pattern

We’ll cover:

  1. What they are

  2. Why they matter in Salesforce

  3. How they work (with Apex code examples)

  4. Practical Salesforce use cases

  5. How they can even be combined


🔹 What is the Singleton Pattern?

The Singleton pattern ensures that only one instance of a class exists during a single Salesforce transaction.

👉 Think of it like Salesforce’s Governor Limits: since resources are limited, you don’t want to repeatedly query the same data or create the same object multiple times in a single execution context.

⚙️ How Singleton Works

  1. Private constructor → prevents direct instantiation of the class.

  2. Static variable → stores the single instance.

  3. Public static method → provides global access to the instance.


✅ Apex Example: Singleton for Organization Settings

public class OrgSettingsSingleton {
private static OrgSettingsSingleton instance;
public String orgName {get; private set;}
public String defaultCurrency {get; private set;}

// Step 1: Private constructor (no direct new keyword allowed)
private OrgSettingsSingleton() {
orgName = [SELECT Name FROM Organization LIMIT 1].Name;
defaultCurrency = UserInfo.getDefaultCurrency();
}

// Step 2: Public static method to get the single instance
public static OrgSettingsSingleton getInstance() {
if (instance == null) {
instance = new OrgSettingsSingleton();
}
return instance;
}
}

📌 Salesforce Use Case:

Suppose you need the Org Name and Default Currency multiple times in a trigger, batch, or controller. Instead of running the SOQL query every time, the Singleton ensures:

  • Only one query runs per transaction

  • The data is reused globally

  • You save on SOQL governor limits


🔹 What is the Factory Pattern?

The Factory pattern is a creational pattern that lets you create objects without exposing the creation logic to the client.

Instead of using if-else or switch statements everywhere in your code, the Factory centralizes object creation. This makes your code cleaner, extensible, and easier to maintain.


⚙️ How Factory Works

  1. Define a common interface (or abstract class).

  2. Create multiple implementations of that interface.

  3. Use a Factory class to decide which implementation to return at runtime.


✅ Apex Example: Factory for Notifications

// Step 1: Define an interface
public interface Notification {
void send(String message);
}

// Step 2: Create multiple implementations
public class EmailNotification implements Notification {
public void send(String message) {
Messaging.SingleEmailMessage email = new Messaging.SingleEmailMessage();
email.setSubject(‘Factory Pattern Demo’);
email.setPlainTextBody(message);
email.setToAddresses(new String[] {‘test@example.com’});
Messaging.sendEmail(new Messaging.SingleEmailMessage[] {email});
}
}

public class SMSNotification implements Notification {
public void send(String message) {
System.debug(‘SMS Sent: ‘ + message);
}
}

// Step 3: Factory class
public class NotificationFactory {
public static Notification getNotification(String type) {
if (type == ‘EMAIL’) {
return new EmailNotification();
} else if (type == ‘SMS’) {
return new SMSNotification();
} else {
throw new IllegalArgumentException(‘Invalid notification type’);
}
}
}


📌 Salesforce Use Case:

Imagine a Case Escalation process where customers can be notified via Email or SMS depending on their preferences.

Instead of writing:

if(channel == 'EMAIL') { ... } else if(channel == 'SMS') { ... }

all over your code, you simply call:

Notification notify = NotificationFactory.getNotification(channel);
notify.send('Your case has been escalated');

If a new channel (like WhatsApp) is added later, you just:

  1. Create a new WhatsAppNotification class implementing Notification.

  2. Update the NotificationFactory.

No need to touch the main business logic.


🔹 Combining Singleton and Factory

In some cases, you may want to ensure that only one factory instance exists across the transaction (for efficiency).


✅ Example: Singleton Factory

public class NotificationFactorySingleton {
private static NotificationFactorySingleton instance;

private NotificationFactorySingleton() {}

// Singleton Instance
public static NotificationFactorySingleton getInstance() {
if (instance == null) {
instance = new NotificationFactorySingleton();
}
return instance;
}

// Factory Method
public Notification getNotification(String type) {
return NotificationFactory.getNotification(type);
}
}


📌 Real-World Salesforce Use Case

🔔 Case Management Notification System

  • The system decides the notification channel at runtime (Factory).

  • Only one instance of the factory should exist during a transaction to prevent repeated initialization (Singleton).

So, when a Case escalates:

NotificationFactorySingleton factory = NotificationFactorySingleton.getInstance();
Notification notify = factory.getNotification(userPreferredChannel);
notify.send('Your case has been updated.');

This ensures efficiency + flexibility in one design.


🚀 Key Takeaways

  • Singleton Pattern

    • Ensures only one instance per transaction

    • Useful for caching, org-wide settings, and reducing SOQL queries

  • Factory Pattern

    • Centralizes object creation logic

    • Useful for dynamic behavior like notifications, integrations, payment gateways

  • Combination

    • Singleton Factory provides both performance optimization and scalability

By using these patterns, Salesforce developers can build enterprise-grade, maintainable, and scalable applications that adhere to best practices and respect governor limits.

Leave a Comment

Your email address will not be published. Required fields are marked *