Skip to main content
New tool CRON Expression Builder — preview next run times before you schedule Apex. Open the builder →
Diagram illustrating the four essential Salesforce Design Patterns for cleaner Apex development workflows
Apex

4 Essential Salesforce Design Patterns for Apex Developers

I've seen way too much spaghetti code in Apex that breaks the second someone touches it. These four design patterns are the ones I reach for every day to keep my code clean and stay within governor limits.

The short answer

Four Apex design patterns (Singleton, Factory, Strategy, and Unit of Work) help Salesforce developers write maintainable code and stay inside governor limits. The article walks through code examples that cut repeated metadata queries, centralize object instantiation, simplify conditional logic, and batch DML operations.

Key takeaways Use the Singleton pattern so configuration and metadata classes are instantiated once per transaction instead of re-running the same SOQL query. Centralize object instantiation in a Factory so business logic never names a concrete class, which pays off once you have several integrations or processors. Replace nested conditionals and a switch statement that keeps growing with the Strategy pattern, which puts each interchangeable business rule in its own testable class. Use the Unit of Work pattern to track record changes and commit them in one batch at the end of the transaction, which keeps DML out of your loops.

I've spent years looking at messy Apex code, and the thing that saves my sanity is using the right Salesforce design patterns. We've all been there. You open a class that ten different developers have touched and it's a mountain of spaghetti logic: hard to read, impossible to test, and probably one record away from hitting a governor limit.

Design patterns are practical tools that help you write code that doesn't break every time someone breathes on it. In my experience, you don't need to know every pattern in the book. There are four I use almost every single day.

Why you need Salesforce design patterns in your Apex code

Apex isn't Java or C#. We're running on a multi-tenant platform where every CPU millisecond and SOQL query counts. If you're constantly re-querying the same metadata or building massive if-else chains, you're going to run into trouble. Using established Salesforce design patterns helps you stay under those asynchronous Apex limits and makes your code much easier to hand off to the next dev.

1. The Singleton Pattern

This is probably the most common pattern I use. The goal is simple: make sure a class only gets instantiated once during a single transaction. I see people query Custom Metadata or Custom Settings inside a loop all the time, which is a great way to burn through your limits. With a Singleton, you load it once and you're done.

public class AppConfig {
    private static AppConfig instance;
    public String apiKey;
    public String endpoint;

    private AppConfig() {
        App_Settings__mdt setting = [SELECT API_Key__c, Endpoint__c FROM App_Settings__mdt LIMIT 1];
        apiKey = setting.API_Key__c;
        endpoint = setting.Endpoint__c;
    }

    public static AppConfig getInstance() {
        if (instance == null) {
            instance = new AppConfig();
        }
        return instance;
    }
}

Whenever you need that API key, you call AppConfig.getInstance().apiKey. Call it once or a hundred times; that SOQL query only runs once. It's a small win that adds up fast in a complex Apex Trigger.

A professional system architecture diagram on a computer screen showing the logical flow of a software design pattern.

The logical flow of a design pattern, drawn out as an architecture diagram.

2. The Factory Pattern

One thing that trips people up is having too many "new" keywords scattered across their codebase. The Factory pattern centralizes how you create objects. I find this helpful when I'm dealing with different types of integrations or payment processors. The calling code doesn't have to know which class to use, because the Factory decides.

public class PaymentFactory {
    public static PaymentProcessor getProcessor(String type) {
        if (type == 'PayPal') return new PayPalProcessor();
        if (type == 'Stripe') return new StripeProcessor();
        throw new IllegalArgumentException('We dont support this payment type yet.');
    }
}

This makes your life much easier when the business decides to add a third payment option. You update the Factory, and you don't have to hunt through twenty different classes to change the logic. It's clean, and it keeps your business logic separated from your object creation.

Mastering common Salesforce design patterns

The next two patterns are about handling complex business rules and data operations without making a mess.

3. The Strategy Pattern

I've seen teams build 500-line methods full of nested if-else statements to handle regional tax rules or discount logic. It's a nightmare to maintain. The Strategy pattern lets you pull those "strategies" into their own classes and swap them out at runtime based on what you need.

Practical tip: If you find yourself writing a switch statement that keeps growing every month, that's a huge red flag. You should probably be using the Strategy pattern instead.

By using an interface, you can have a USDiscountStrategy and a UKDiscountStrategy. Your main code doesn't care which one it's using; it just knows it can call apply(). Unit testing gets much easier because you can test each rule in isolation.

4. The Unit of Work Pattern

This is the big one for anyone doing a Salesforce API integration or complex data processing. The Unit of Work pattern tracks every change you want to make (inserts, updates, deletes) and commits them all at once at the very end.

Why bother? Because it keeps you out of the "DML in a loop" trap. It also gives you better control over the rollback if one part of your transaction fails. Most people use the fflib implementation, but even a simple custom version can save you from hitting governor limits when your data volume starts to scale.

public class UnitOfWork {
    private List<Account> accsToUpdate = new List<Account>();
    
    public void registerDirty(Account acc) {
        accsToUpdate.add(acc);
    }

    public void commitWork() {
        if (!accsToUpdate.isEmpty()) {
            update accsToUpdate;
        }
    }
}

Key takeaways

  • Singleton: Best for shared config and saving SOQL queries on metadata.
  • Factory: Use this to stop hardcoding class names and centralize object creation.
  • Strategy: Perfect for replacing long, messy if-else blocks with clean, swappable logic.
  • Unit of Work: Your best friend for batching DML and keeping transactions consistent.

These Salesforce design patterns are about making your future self's life easier. We've all had to fix a bug in a class we wrote six months ago and thought, "What was I thinking?" Patterns give you a roadmap so you don't have to reinvent the wheel every time you start a new project. Start small. Try a Singleton in your next trigger and you'll see the difference in your code quality pretty quickly.

Frequently asked questions

When should you use the Singleton pattern in Apex?

Use the Singleton pattern for shared resources such as Custom Metadata or Custom Settings that only need to be queried once in a transaction.

How does the Factory pattern work in Salesforce Apex?

The Factory pattern centralizes object instantiation in a dedicated class method that returns the right instance for the input parameters, so the calling code never names a concrete class.

Why should you use the Strategy pattern in Salesforce?

The Strategy pattern replaces nested if-else chains and large switch statements by putting each interchangeable business rule in its own class behind a common interface.

How does the Unit of Work pattern prevent DML inside loops?

The Unit of Work pattern registers database operations as records change through your business logic, then runs all the inserts, updates, and deletes together in one bulk commit at the end of the transaction.

Newsletter

One email every Tuesday

New guides, tool updates, and the release-note changes that break things.

No spam. Unsubscribe in one click.

Comments

Loading comments...

Leave a Comment