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)