Design Pattern: Strategy Pattern

Summary

Pattern NameStrategy Pattern
Pattern TypeBehavioral Pattern
Other NamesPolicy
ScopeObject
TaglineUse an algorithm from a group of interchangeable algorithms
Use casesWherever there are multiple algorithms to serve a similar purpose
Related PatternsFactory
Decorator
Difficulty LevelMedium
Implementations

Definition

When there is a group of similar algorithms and we need a pattern to decide among those patterns, then we can use Strategy pattern.

Using Strategy pattern we can decide which algorithm to use, on the fly. The existing classes are not changed while implementing Strategy pattern, a new Strategy class is introduced, which handles the operations.

Strategy pattern makes the algorithms interchangeable and lets them vary independently from client to client.

The client must be aware of the differences between different Strategy(algorithm) objects. Without knowing the differences the client can not decide when to use which algorithm.

If we want to add/introduce a new algorithm to the system, then we just need to create that algorithm class and implement the strategy interface for the class. No other change will be required. So introducing new algorithms becomes very easy.

Use Cases

Here are a few use cases of the Strategy pattern-

  • When there are multiple related classes (which differ in their behavior), and we need to use any one of them in certain cases.
  • When we need multiple variations of the same algorithm and we want to decide their usage at run-time.
  • When we want to avoid specifying an algorithm usage strictly at a certain case.

Implementation

Strategy pattern has 3 elements:

  1. Item Algorithm Interface: interface to make sure the same type for all Item Concrete classes (algorithm classes).
  2. Item Concrete Classes (algorithm classes): algorithm classes implementing the Item Interface.
  3. Strategy Class: class that takes the algorithm instance(in the constructor), and then uses that algorithm for performing operations on that algorithm classes. This strategy class uses/calls the functions from the algorithm class (may include some additional operations).

Use the following steps and criteria to implement Strategy pattern.

  1. Make sure the different classes implement the same interface and are supposed to be used for the same purpose.
  2. Create a class to implement the strategy process.
  3. The constructor of Strategy class takes parameters to know which one of the classes, the user wants to use.
  4. Add any required functions in the strategy class, and use the functions from the actual implementations. As the reference of the actual implementation class is stored in the strategy class, so that reference can be used to call functions from those actual classes.
  5. While using the Strategy class, pass an instance of the actual that you want to use. Like, new StrategyClass(new ActualStrategyClass1()).
  6. The client uses functions from the strategy class and does not use functions from actual/algorithm classes directly.

The Strategy class does not need to use all the functions from the actual classes/algorithms. Only the required functions will be used.

In the implementation(& usage), Strategy pattern creates two objects – one is of the Strategy Class and another is off the Algorithm class. This keeps their concerns separate.

Key points in the implementation are:

  1. The item concrete classes (algorithm classes) implement the same interface.
  2. The strategy class holds a reference of the algorithm class that will be used. That reference is used to execute functions from that algorithm class(item class).

Examples

Example #1: Storage Selection

Let’s consider file storage functionality in an application. Take a look at the class diagram first:

Here we have different ways to store files – Local storage, Google Drive and S3. We will use the Strategy pattern (using StorageStrategy class) to use any of the available storage methods when we need any of these.

Storage Interface

interface Storage

   function storeFile(tempPath): Integer

   retrieveFile(fileId): String

   printFileInfo(fileId)

end interface

Local Storage Class

class LocalStorage implements Storage

    function storeFile(String tempPath): Integer
        // Code to store file here

        // return the ID that is obtained from the database record or any other unique identifier.
        return fileId;
    end function

    function retrieveFile(fileId): String
        // Retrieve the url and return back
        // some dummy url returned for demo
        return "https://bigboxcode.com/files/local/" + fileId
    end function

    function printFileInfo(fileId)
        print("Storage type: Local Storage")
        print("File ID: " + fileId)
        print("File URL: " + retrieveFile(fileId))
    end function

end class

Google Drive Storage Class

class GoogleDriveStorage implements Storage
    
   function storeFile(tempPath): Integer
        // Code to store file here

        // return the ID that is obtained from the database record or any other unique identifier.
        return fileId
    end function

    function retrieveFile(fileId): String
        // Retrieve the url and return back

        // Some dummy url is returned for demo purpose
        return "https://drive.google.com/file/d/1234_9K7654hu6RT_9j7JKY3fK/view"
    end function

    function printFileInfo(fileId)
        print("Storage type: Google Drive")
        print("File ID: " + fileId)
        print("File URL: " + retrieveFile(fileId))
    end function

end class

AWS S3 Storage Class

class S3Storage implements Storage 
    
    function storeFile(tempPath): Integer
        // Code to store file here

        // return the ID that is obtained from the database record or any other unique identifier.
        return fileId
    end function

    function retrieveFile(fileId): String
        // Retrieve the url and return back

        // Some dummy url is returned for demo purpose
        return "https://bigboxcode.s3.amazonaws.com/pdf/UC-0e7654338-5697-4f99-b33-d89h87g5gf4gwfg.pdf"
    end function

    function printFileInfo(int fileId)
        print("Storage type: AWS S3")
        print("File ID: " + fileId)
        print("File URL: " + retrieveFile(fileId))
    end function

end class

Storage Strategy Class

class StorageStrategy

    var storage: Strategy

    constructor(storageTypeParam: Storage) {
       storage = storageTypeParam
    end constructor

    function uploadFile(tempPath): Integer
        int fileId = storage.storeFile(tempPath)
        storage.printFileInfo(fileId)

        return fileId
    end function

    function getFileUrl(fileId): Integer
        return storage.retrieveFile(fileId)
    end function

end class

Demo

// Use Local Storage
fileStorage: StorageStrategy = new StorageStrategy(new LocalStorage())
fileStorage.uploadFile("/some-temp-path")

// Use S3
fileStorage = new StorageStrategy(new S3Storage())
fileStorage.uploadFile("/some-temp-path")

// Use Google drive
fileStorage = new StorageStrategy(new GoogleDriveStorage())
fileStorage.uploadFile("/some-temp-path")

Code Implementations

Use the following links to check Strategy pattern implementation in specific programming languages.

Leave a Comment


The reCAPTCHA verification period has expired. Please reload the page.