Apex trigger factory pattern

Generic Apex Trigger Factory Pattern   

    This blog explains the salesforce generic code for Trigger Factory Pattern. There are few guidelines to use the trigger for great practices that we should consider before implementing the code.

Some of the best practices are below,

  1. One trigger per object 
  2. Logic fewer triggers
  3. Context-SPecific Handler methods
  4. Bulkify the code
  5. Avoid SOQL query inside FOR Loops
  6. Use Collections, Streamlining Queries, and Efficient For Loops
  7. Querying Large Data sets
  8. Use @future appropriately
  9. Avoid HardCoding IDs

Why do we need a trigger pattern?

    This pattern enforces the logical sequence to the trigger code and in turn, helps to keep the code tidy and more maintainable. Keeping the trigger logic for each object in a single place avoids the multiple triggers that are in contention with each other and is easy to debug and avoids the repetitive SOQL queries that can exceed the governor limits.

Trigger Context variables :






Create below Apex classes and Trigger,

  • InterfaceTrigger
  • TriggerFactory
  • TriggerException
  • ContactTrigger
  • ContactTriggerHandler
InterfaceTrigger apex class is used to cache the data before and after context.

public interface InterfaceTrigger {

void bulkBefore();
void bulkAfter();
// As per the trigger context execution only new list available before record insert
void beforeInsert(List<SObject> newlistObject);
// As per the trigger context execution newList,oldList,newMap and oldMap values
are available before record update
void beforeUpdate(List<SObject> newlistObject,List<SObject> oldlistObject,
Map<Id,SObject> newMapObject,Map<Id,SObject> oldMapObject);
// As per the trigger context execution only oldlist and oldmap available before
record delete
void beforeDelete(List<SObject> oldlistObject, Map<Id,SObject> oldMapObject);
// As per the trigger context execution only newlist and newmap available
after record insert
void afterInsert(List<SObject> newlistObject, Map<Id,SObject> newMapObject);
// As per the trigger context execution newList,oldList,newMap and oldMap values are
available after record update
void afterUpdate(List<SObject> newlistObject,List<SObject> oldlistObject,
Map<Id,SObject> newMapObject,Map<Id,SObject> oldMapObject);
// As per the trigger context execution only oldlist and oldmap available after
record delete
void afterDelete(List<SObject> oldlistObject, Map<Id,SObject> oldMapObject);

// This method will execute only once after all the above method executed.
use below method to update or create other records
void andFinally();
}

TriggerFactory apex class to execute the trigger handler and you can modify the getHandler method to add trigger handler apex classes for other objects.

public with sharing class TriggerFactory {
/**
* this method to execute the trigger handler
* It will throw the error if there is no handler available
*/
public static void createHandler(Schema.sObjectType objType){

InterfaceTrigger IThandler = getHandler(objType);

if (IThandler == null){
throw new TriggerException('There is no Trigger Handler registered for Object Type: ' + objType);
}
execute(IThandler);
}

/**
* this method to control the execution of the handler
*/
private static void execute(InterfaceTrigger IThandler){

// Before Trigger
if (Trigger.isBefore) {
// Call the bulk before to handle any caching of data and enable bulkification
IThandler.bulkBefore();

if (Trigger.isDelete) {
IThandler.beforeDelete(trigger.old,trigger.oldMap);
}

else if (Trigger.isInsert) {
IThandler.beforeInsert(trigger.new);
}

else if (Trigger.isUpdate) {
IThandler.beforeUpdate(trigger.new,trigger.old,trigger.newMap,trigger.oldMap);
}
}else {
// Call the bulk after to handle any caching of data and enable bulkification
IThandler.bulkAfter();

if (Trigger.isDelete) {
IThandler.afterDelete(trigger.old,trigger.oldMap);
}

else if (Trigger.isInsert) {
IThandler.afterInsert(trigger.new,trigger.newMap);
}

else if (Trigger.isUpdate) {
IThandler.afterUpdate(trigger.new,trigger.old,trigger.newMap,trigger.oldMap);
}
}

// Perform any post processing
IThandler.andFinally();
}

/**
* this method to get the appropriate handler for the object type.
* Modify this method to add any additional handlers.
*/
public static InterfaceTrigger getHandler(Schema.sObjectType objType){
if (objType == Contact.sObjectType){
return new ContactTriggerHandler();
}
return null;
}
}

TriggerException apex class to capture the errors

/**
* Capture exception if there is no handler available of the object
*/

public class TriggerException extends Exception {

}


trigger ContactTrigger on Contact (after delete, after insert, after undelete, after update,
before delete, before insert, before update) {
TriggerFactory.createHandler(Contact.sobjectType);
}

ContactTriggerHandler to perform the business logic.

public with sharing class ContactTriggerHandler implements InterfaceTrigger{
/**
* Modify the below events based on the logics
*/
/***************** BEFORE EVETNTS *********************/
public void bulkBefore(){
}
public void beforeInsert(List<Sobject> newContacts){

}

public void beforeUpdate(List<Sobject> newContacts, List<Sobject> oldContacts,
Map<Id, Sobject> newContactMap, Map<Id, Sobject> oldContactMap){

}

public void beforeDelete(List<Sobject> oldContacts,Map<Id,Sobject> oldContactMap){

}

/***************** AFTER EVENTS *********************/
public void bulkAfter(){

}

public void afterInsert(List<Sobject> newContacts,Map<Id,Sobject> newContactMap){
}

public void afterUpdate(List<Sobject> newContacts,List<Sobject> oldContacts,
Map<Id,Sobject> newContactMap, Map<Id,Sobject> oldContactMap){

}

public void afterDelete(List<Sobject> oldContacts,Map<Id,Sobject> oldContactMap){

}


/**************** FINAL EXECUTION ******************/
public void andFinally(){}
}









Popular posts from this blog

How to extract information from xml using node.js

salesforce questions and answers

How to clone a record using custom button in salesforce