The strategy pattern

This design pattern is also referred to as the policy pattern saying policy to be selected at runtime.

Note

The strategy design pattern is used to determine an algorithm at runtime to solve a problem.

We will continue with the example of the Music Library portal, as discussed in the visitor pattern and observer pattern. As part of the implementation, developers want to add support for payment in the shopping cart. However, the customer's selected payment type can be known only during a checkout. Customers can use either a credit card, debit card, or PayPal. Let's see how the strategy pattern can come in handy in this situation.

For this example, let's consider the following structure for a song (a Music Library custom object), which can be added to the shopping cart:

The strategy pattern

The following interface needs to be implemented by all the payment methods so that it can be selected at runtime:

/* 
* This interface needs to be implemented by all classes 
 * of Payment types which needs to be decided at runtime 
 * */ 
public interface PaymentStrategy { 
     void pay(Double amount); 
} 

The following concrete class implements the PaymentStrategy interface to process the payment using credit cards:

/* 
* This class is used to pay using credit card 
 * */ 
public class CreditCardStrategy implements PaymentStrategy{ 
     
    private String name; 
    private String cardNumber; 
    private String cvv; 
    private String dateOfExpiry; 
     
    /* Constructor */ 
    public CreditCardStrategy(String name, String cardNumber, String cvv, String dateOfExpiry){ 
        this.name = name; 
        this.cardNumber = cardNumber; 
        this.cvv = cvv; 
        this.dateOfExpiry = dateOfExpiry;         
    } 
     
    /* method from inteface PaymentStrategy */  
    public void pay(Double amount){ 
        System.debug('Web service callout to pay using credit card') ; 
    } 
} 

The following concrete class implements the PaymentStrategy interface to process the payment using PayPal:

/* 
* This class is used to pay using Paypal 
 * */ 
public class PaypalStrategy implements PaymentStrategy{ 
     
    private String emailId ; 
    private String password; 
     
    /* Constructor */ 
    public PaypalStrategy(String emailId , String password){ 
        this.emailId = emailId; 
        this.password = password; 
    } 
     
    /* Overrided method from inteface PaymentStrategy */  
    public void pay(Double amount){ 
        System.debug('Web service callout to pay using paypal Account') ; 
    } 
} 

The following concrete class implements the PaymentStrategy interface to process the payment using debit cards:

/* 
* This class is used to pay using debit card 
 * */ 
public class DebitCardStrategy implements PaymentStrategy{ 
    
    private String name; 
    private String cardNumber; 
    private String pin;  
     
    /* Constructor */ 
    public DebitCardStrategy(String name, String cardNumber, String pin){ 
        this.name = name; 
        this.cardNumber = cardNumber; 
        this.pin = pin; 
    } 
     
    /* method from inteface PaymentStrategy */  
    public void pay(Double amount){ 
        System.debug('Web service callout to pay using Debit Card') ; 
    }     
} 

The following class is used to add or remove songs in the shopping cart, and initiate the payment process:

/* 
* This class is used calculate payment amount 
 * */ 
public class ShoppingCart { 
     
    List<Music_Library__c> lstSongs ; 
         
    /*Constructor*/ 
    public ShoppingCart() 
    { 
        lstSongs = new List<Music_Library__c>(); 
    } 
     
    /* Add music in cart */ 
    public void addSong(Music_Library__c m){ 
        lstSongs.add(m); 
    } 
     
    /* Remove music song from cart */ 
    public void removeSong(Music_Library__c songToRemove){ 
        Integer index = -1 ;  
        for(Music_Library__c m : lstSongs) 
        { 
            index ++; 
            if(m.Id == songToRemove.Id){ 
                lstSongs.remove(index); 
                break ; 
            } 
        } 
         
    } 
     
    /* Calculate total amount and pay using selected mechanism*/ 
    public void pay(PaymentStrategy payMethod){ 
        Double finalAmount = 0; 
         
        for(Music_Library__c m : lstSongs) 
        { 
            finalAmount = finalAmount+m.price__c ; 
        } 
       System.debug('Total amount to be paid - '+finalAmount) ; 
        payMethod.pay(finalAmount) ; 
    } 
} 

Let's create a sample record first in the Music_Library__c object by running the following code in an anonymous Apex:

List<Music_Library__c> lstSongs = new List<Music_Library__c>(); 
lstSongs.add(new Music_Library__c(Title__c='Go Johnny go',  
                                  Album__c='Chuck Berry Is on Top',  
                                  price__c= 2.0)); 
 
lstSongs.add(new Music_Library__c(Title__c='When Doves Cry',  
                                  Album__c='The Very Best Of Prince',  
                                  price__c= 2.5)); 
 
lstSongs.add(new Music_Library__c(Title__c='Strobe',  
                               Album__c='For Lack of a Better Name',  
                                  price__c= 2.0)); 
 
insert lstSongs ; 

Assume that the preceding three songs are added to the shopping cart of a user and they want to make a payment using a credit card. The following code can be executed in an anonymous window of the developer console to see how it works:

List<Music_Library__c> lstSongs = [SELECT ID,price__c FROM Music_Library__c LIMIT 3] ; 
 
ShoppingCart cart = new ShoppingCart(); 
for(Music_Library__c m : lstSongs) 
{ 
   cart.addSong(m) ; 
} 
 
cart.pay(new CreditCardStrategy('Customer Name', '1234567891234567', '123', '11/2016')); 

The output will be as follows:

Total amount to be paid - 6.5 
Web service callout to pay using credit card 

In the same way, if we want to pay using PayPal, then we only need to change one line that calls the pay() methods, as shown in the following code:

List<Music_Library__c> lstSongs = [SELECT ID,price__c FROM Music_Library__c LIMIT 3] ; 
 
ShoppingCart cart = new ShoppingCart(); 
for(Music_Library__c m : lstSongs) 
{ 
   cart.addSong(m) ; 
} 
cart.pay(new PaypalStrategy('[email protected]', 'StrongPwd' )); 

The output is as follows:

Total amount to be paid - 6.5 
Web service callout to pay using PayPal Account 

The following class diagram shows the overall structure of classes that we have used:

The strategy pattern

As we have seen in the preceding example, it is very easy to choose a payment method (algorithm) at runtime using the strategy pattern.

Points to consider

  • The state pattern is like the strategy pattern except in its intent.
  • The strategy pattern lets you change the core of an object. However, the decorator pattern lets you change the skin (wrapper).
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset