Friday, May 29, 2015

Implementing Singleton Design Pattern in Apex - Use Case I


This post is part of the series - Design Pattern in Apex
Singleton Design Pattern is pretty popular and one of the simplest design pattern available.
I will start with the statement from “The Gang of Four” as it describes Singleton Pattern as  –
“Ensure a class has only one instance, and provide a global point of access to it.”

In this post, I will explain why we need to have Singleton Design Pattern in Apex and how to implement the same.

Sometimes it is very much required to have only instances of the class – Logger, Window Manager etc. Typically, these type of objects where only one instance is sufficient to handle the requirements, are called Singleton.

With Singleton Design Pattern, you can –
  • Ensure that only one instance of class is getting created.
  • Provide a global point of access to the object.
There are many ways to implement Singleton Pattern in apex. Let’s start with few case scenarios:

Use Case:
Consider the below requirement -
Whenever a new account is getting inserted to Salesforce, it should be synced with MDM(Master Data Management) through integration. But if MDM system is down, then Salesforce should not got for synchronization.

Let's start implementing the requirement -

Custom Settings - Integration - This will be used to identify whether MDM System is up and running. If MDM System is down, Admin will uncheck the value and then Salesforce will not try for synchronization. Below is how custom settings will look like -
AccountTriger-

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
trigger MyAccountTrigger on Account (before insert) {
 for(Account anAccount : Trigger.new){
  AccountHelper myAccountHelper = new AccountHelper();
  if(myAccountHelper.isSyncEnabled){
   //Call Sync Methods
  }else{
   //Do nothing
  }
 }
}

AccountHelper -

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
public with sharing class AccountHelper {
 public Boolean isSyncEnabled {get;private set;}
 
 public AccountHelper(){
  Integration__c mdmIntegration = Integration__c.getValues('MDM');
  isSyncEnabled = mdmIntegration.isEnabled__c;
 }
}

Now if you test, this code will work fine. But this code is having a very basic problem.

Let's understand the problem first by going through the trigger. Consider line#2 where we are iterating through the list of accounts via Trigger.new. Now think of a scenario where we are inserting huge amount of accounts through dataloader. So in that case Trigger.new will return us huge list and we will iterate through each account and create an instance of our AccountHelper class.

Now inside AccountHelper class constructor, we are checking values from our custom settings.

So what will happen, for all the records, we will create a new instance and query custom object every time. Do you think this is really necessary?

Definitely not. But why? The reason is that in the same transaction, we don't need to create multiple instances and check custom settings every time. In a single transaction, if Trigger.new is returning us a list of 200 accounts, we should create a single instance of AccountHelper class which will query our custom objects once. Great!! But now the question is how we can achieve that ??

Below is the updated code -
AccountTrigger -

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
trigger MyAccountTrigger on Account (before insert) {
 for(Account anAccount : Trigger.new){
  AccountHelper myAccountHelper = AccountHelper.getAccountHelperInstance();
  if(myAccountHelper.isSyncEnabled){
   //Call Sync Methods
  }else{
   //Do nothing
  }
 }
}
AccountHelper -

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
public with sharing class AccountHelper {
 private static AccountHelper accountHelperInstance = null;
 public Boolean isSyncEnabled {get; private set;}
 
 private AccountHelper(){
  Integration__c mdmIntegration = Integration__c.getValues('MDM');
  isSyncEnabled = mdmIntegration.isEnabled__c;
 }
 
 public static AccountHelper getAccountHelperInstance(){
  if(accountHelperInstance==null){
   accountHelperInstance = new AccountHelper();
  }
  return accountHelperInstance;
 }
}

Below are the changes -
  • The static getAccountHelperInstance() method will only instantiate an instance of the class if it doesn't already exists. 
  • The constructor and accountHelperInstance variable is private, which will make sure that it cannot be instantiated outside of the getAccountHelperInstance() method.
I hope this will help you to understand why we need Singleton Design Pattern. I will write few more use cases in my next posts. Till then if you have any feedback, please let me know. 

Wishing you a happy learning.


           

1 comment:

  1. thank you for sharing....now this is the time to lead your life then learn Dot Net Training in Chennai get a IT JOB easily.more details Dot Net Training in Chennai

    ReplyDelete