Monday, March 4, 2024

Salesforce Apex: Factory and Strategy Patterns

Factory Pattern

The Factory Pattern is a creational design pattern that provides an interface for creating objects in a superclass, but allows subclasses to alter the type of objects that will be created. In Salesforce Apex, you can use the Factory Pattern to encapsulate the object creation process and to promote loose coupling, thereby making your code more modular, flexible, and maintainable.

To utilize the Factory Pattern in Salesforce Apex, you can define an interface or an abstract class with a method declaration that subclasses or implementing classes will use to create instances of objects. Here's an example to illustrate the Factory Pattern in Salesforce Apex:

Suppose you have different types of notifications that you want to send from Salesforce, such as EmailNotification, SMSNotification, and PushNotification. You can create a factory to generate these notification instances based on the type required.

Step 1: Define an interface with a method to send notifications.

public interface INotification {
    void send(String message);
}

Step 2: Implement the interface with different notification types.

public class EmailNotification implements INotification {
    public void send(String message) {
        // Logic to send email notification
        System.debug('Email notification sent: ' + message);
    }
}

public class SMSNotification implements INotification {
    public void send(String message) {
        // Logic to send SMS notification
        System.debug('SMS notification sent: ' + message);
    }
}

public class PushNotification implements INotification {
    public void send(String message) {
        // Logic to send push notification
        System.debug('Push notification sent: ' + message);
    }
}

Step 3: Create a Factory class to generate instances of the notifications.

public class NotificationFactory {
    public enum NotificationType {
        EMAIL, SMS, PUSH
    }

    public static INotification getNotificationInstance(NotificationType type) {
        switch on type {
            when EMAIL {
                return new EmailNotification();
            }
            when SMS {
                return new SMSNotification();
            }
            when PUSH {
                return new PushNotification();
            }
            when else {
                throw new IllegalArgumentException('Invalid notification type');
            }
        }
    }
}

Step 4: Use the Factory to get instances and send notifications.

public class NotificationService {

    public void sendNotification(NotificationFactory.NotificationType type, String message) {
        INotification notification = NotificationFactory.getNotificationInstance(type);
        notification.send(message);
    }
}

To test this pattern, you can write a test method that uses the NotificationService to send different types of notifications:

@IsTest
private class NotificationServiceTest {
    @IsTest static void testSendNotifications() {
        NotificationService service = new NotificationService();
        
        // Test sending email notification
        service.sendNotification(NotificationFactory.NotificationType.EMAIL, 'Test email message');
        
        // Test sending SMS notification
        service.sendNotification(NotificationFactory.NotificationType.SMS, 'Test SMS message');
        
        // Test sending push notification
        service.sendNotification(NotificationFactory.NotificationType.PUSH, 'Test push message');
    }
}

With this setup, adding a new notification type requires you to create a new class that implements INotification and update the NotificationFactory to handle the new type. This design adheres to the open/closed principle, one of the SOLID principles, making it easy to extend the functionality without modifying existing code.

Strategy Pattern

The Strategy Pattern is a behavioral design pattern that enables selecting an algorithm's behavior at runtime. Instead of implementing a single algorithm directly, code receives run-time instructions as to which in a family of algorithms to use.

In the context of your Salesforce Apex example with notifications, you can use the Strategy Pattern to define a set of interchangeable algorithms for sending notifications. The client code can then choose the appropriate algorithm based on the context.

Here’s an example to illustrate the Strategy Pattern in Salesforce Apex:

Step 1: Define an interface with a method to send notifications, just like in the Factory Pattern example.

public interface INotificationStrategy {
    void send(String message);
}

Step 2: Implement the interface with different strategies for sending notifications.

public class EmailNotificationStrategy implements INotificationStrategy {
    public void send(String message) {
        // Logic to send email notification
        System.debug('Email notification sent: ' + message);
    }
}

public class SMSNotificationStrategy implements INotificationStrategy {
    public void send(String message) {
        // Logic to send SMS notification
        System.debug('SMS notification sent: ' + message);
    }
}

public class PushNotificationStrategy implements INotificationStrategy {
    public void send(String message) {
        // Logic to send push notification
        System.debug('Push notification sent: ' + message);
    }
}

Step 3: Create a context class that uses a notification strategy.

public class NotificationContext {
    private INotificationStrategy strategy;

    // Constructor to set the strategy
    public NotificationContext(INotificationStrategy strategy) {
        this.strategy = strategy;
    }

    // Method to send notification using the strategy
    public void sendNotification(String message) {
        strategy.send(message);
    }

    // Method to change the strategy at runtime
    public void setStrategy(INotificationStrategy strategy) {
        this.strategy = strategy;
    }
}

Step 4: Use the context class to send notifications.

public class NotificationSender {

    public void sendNotification(String type, String message) {
        INotificationStrategy strategy;

        if (type == 'EMAIL') {
            strategy = new EmailNotificationStrategy();
        } else if (type == 'SMS') {
            strategy = new SMSNotificationStrategy();
        } else if (type == 'PUSH') {
            strategy = new PushNotificationStrategy();
        } else {
            throw new IllegalArgumentException('Invalid notification type');
        }

        NotificationContext context = new NotificationContext(strategy);
        context.sendNotification(message);
    }
}

In this example, NotificationSender is responsible for selecting the appropriate strategy based on the notification type and then using a NotificationContext to send the message.

To test this pattern, you can write a test method that sends different types of notifications:

@IsTest
private class NotificationSenderTest {
    @IsTest static void testSendNotifications() {
        NotificationSender sender = new NotificationSender();
        
        // Test sending email notification
        sender.sendNotification('EMAIL', 'Test email message');
        
        // Test sending SMS notification
        sender.sendNotification('SMS', 'Test SMS message');
        
        // Test sending push notification
        sender.sendNotification('PUSH', 'Test push message');
    }
}

Difference between Factory and Strategy Patterns:

  • Factory Pattern is a creational pattern used to create objects. It hides the instantiation logic of the classes and refers to the newly created object through a common interface. The client doesn't know about which concrete class is being instantiated.
  • Strategy Pattern is a behavioral pattern used to select an algorithm's behavior at runtime. It defines a family of algorithms, encapsulates each one, and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it.

In the given examples, the Factory Pattern would be used if you wanted a single point (the factory class) to handle the instantiation of notification objects, while the Strategy Pattern is used when the algorithm for sending the notification can be chosen at runtime by the client code. With Strategy, you define a context in which different strategies can be applied, and you can switch between them as needed.

(This blog post is generated by ChatGPT)

Share This:    Facebook Twitter

0 comments:

Post a Comment

Total Pageviews

My Social Profiles

View Sonal's profile on LinkedIn

Tags

__proto__ $Browser Access Grants Accessor properties Admin Ajax AllowsCallouts Apex Apex Map Apex Sharing AssignmentRuleHeader AsyncApexJob Asynchronous Auth Provider AWS Callbacks Connected app constructor Cookie CPU Time CSP Trusted Sites CSS Custom settings CustomLabels Data properties Database.Batchable Database.BatchableContext Database.query Describe Result Destructuring Dynamic Apex Dynamic SOQL Einstein Analytics enqueueJob Enterprise Territory Management Enumeration escapeSingleQuotes featured Flows geolocation getGlobalDescribe getOrgDefaults() getPicklistValues getRecordTypeId() getRecordTypeInfosByName() getURLParameters Google Maps Governor Limits hasOwnProperty() Heap Heap Size IIFE Immediately Invoked Function Expression Interview questions isCustom() Javascript Javascript Array jsForce Lightning Lightning Components Lightning Events lightning-record-edit-form lightning:combobox lightning:icon lightning:input lightning:select LockerService Lookup LWC Manual Sharing Map Modal Module Pattern Named Credentials NodeJS OAuth Object.freeze() Object.keys() Object.preventExtensions() Object.seal() Organization Wide Defaults Override PDF Reader Performance performance.now() Permission Sets Picklist Platform events Popup Postman Primitive Types Profiles Promise propertyIsEnumerable() prototype Query Selectivity Queueable Record types Reference Types Regex Regular Expressions Relationships Rest API Rest Operator Revealing Module Pattern Role Hierarchy Salesforce Salesforce Security Schema.DescribeFieldResult Schema.DescribeSObjectResult Schema.PicklistEntry Schema.SObjectField Schema.SObjectType Security Service Components Shadow DOM Sharing Sharing Rules Singleton Slots SOAP API SOAP Web Services SOQL SOQL injection Spread Operator Star Rating stripInaccessible svg svgIcon Synchronous this Token Triggers uiObjectInfoApi Upload Files VSCode Web Services XHR
Scroll To Top