Apex Design Patterns in Salesforce

Apex Design Patterns in Salesforce

Singleton:
The Singleton pattern attempts to solve the issue of repeatedly using an object instance, but only wishing to instantiate it once within a single transaction context.

Sample Code:

Apex Class:

public class Utility {
    
    public static Utility objInstance = null;
    public Integer acctCount;
    
    public Utility() {
        acctCount = [ SELECT COUNT() FROM Account ];
    }
    
    public static Utility getInstance() {
        if ( objInstance == null )
            objInstance = new Utility();
        return objInstance;
    }
    
}

If you execute the below code, the SOQL will be executed only once.

for ( Integer i = 0; i < 3; i++ ) {
    Utility obj = Utility.getInstance();
    system.debug('Count is ' + obj.acctCount);
}

Strategy:
Defining a family of algorithms, enscapsulating each one and making them interchangeable and selectable at runtime.

Sample Code:

1. Create an interface.

public interface Strategy {

   Integer doOperation(Integer num1, Integer num2);
   
}

Create concrete classes implementing the same interface.

public class OperationAdd implements Strategy {

   public Integer doOperation(Integer num1, Integer num2) {
      return num1 + num2;
   }
   
}

Another class which does subtraction.

public class OperationSubstract implements Strategy {


   public Integer doOperation(Integer num1, Integer num2) {
      return num1 - num2;
   }
   
}

Create Context Class.

public class Context {

   private Strategy strategy;

   public Context(Strategy strategy) {
      this.strategy = strategy;
   }

   public Integer executeStrategy(Integer num1, Integer num2) {
      return strategy.doOperation(num1, num2);
   }
   
}

Use the Context to see change in behaviour when it changes its Strategy.

Context context = new Context(new OperationAdd());
System.debug('10 + 5 = ' + context.executeStrategy(10, 5));

context = new Context(new OperationSubstract());
System.debug('10 - 5 = ' + context.executeStrategy(10, 5));

Decorator:
Extending the functionality of an sObject in Apex.

Example is Wrapper Class

Facade:
Simplifying the execution of classes with complex interfaces (e.g. web service callouts).

Sample Code:

/* Complex parts */

class CPU {
    public void freeze() { ... }
    public void jump(long position) { ... }
    public void execute() { ... }
}

class HardDrive {
    public byte[] read(long lba, int size) { ... }
}

class Memory {
    public void load(long position, byte[] data) { ... }
}


/* Facade */

class ComputerFacade {
    private CPU processor;
    private Memory ram;
    private HardDrive hd;

    public ComputerFacade() {
        this.processor = new CPU();
        this.ram = new Memory();
        this.hd = new HardDrive();
    }

    public void start() {
        processor.freeze();
        ram.load(BOOT_ADDRESS, hd.read(BOOT_SECTOR, SECTOR_SIZE));
        processor.jump(BOOT_ADDRESS);
        processor.execute();
    }
}

/* Client */

class You {
    public static void main(String[] args) {
        ComputerFacade computer = new ComputerFacade();
        computer.start();
    }
}

Composite:

Treating a group of objects in a similar manner to a single instance of that object. Composite pattern is used where we need to treat a group of objects in similar way as a single object. Composite pattern composes objects in term of a tree structure to represent part as well as whole hierarchy. This type of design pattern comes under structural pattern as this pattern creates a tree structure of group of objects.

Sample Code:

Apex Class:

public class Employee {

   private String name;
   private String dept;
   private Integer salary;
   private List<Employee> subordinates;


   // constructor
   public Employee(String name,String dept, Integer sal) {
      this.name = name;
      this.dept = dept;
      this.salary = sal;
      subordinates = new List < Employee >();
   }

   public void add(Employee e) {
      subordinates.add(e);
   }

   public List<Employee> getSubordinates() {
     return subordinates;
   }

}

Execute the below code to set the hierarchy and view the debug log.

Employee CEO = new Employee('John','CEO', 30000);

Employee headSales = new Employee('Robert','Head Sales', 20000);

Employee headMarketing = new Employee('Michel','Head Marketing', 20000);

Employee clerk1 = new Employee('Laura','Marketing', 10000);
Employee clerk2 = new Employee('Bob','Marketing', 10000);

Employee salesExecutive1 = new Employee('Richard','Sales', 10000);
Employee salesExecutive2 = new Employee('Rob','Sales', 10000);

CEO.add(headSales);
CEO.add(headMarketing);

headSales.add(salesExecutive1);
headSales.add(salesExecutive2);

headMarketing.add(clerk1);
headMarketing.add(clerk2);

//print all employees of the organization
System.debug(CEO); 

for ( Employee headEmployee : CEO.getSubordinates() ) {
    System.debug(headEmployee);
    
    for ( Employee employee : headEmployee.getSubordinates() ) {
        System.debug(employee);
    }
    
}

Bulk State Transition:
Efficiently tracking the change of a field value in a trigger and executing functionality based on this change.

Example is bulking the trigger.

Leave a Reply