Introduction

In this new article, we will talk about the Strategy Design Pattern. It’s a behavioral type design pattern that is widely used in the world of programming to solve well-defined problems. It allows you to encapsulate and interchange algorithms while taking care to define them as a family/group of algorithms. These algorithms are similar but have different implementations. It allows an object to dynamically change its behavior depending on the context in which it is located. In the remainder of this article, we present the context in which it can be used, take a case study, and implement this pattern using the Java programming language.

The YouTube Channels in both English (En) and French (Fr) are now accessible, feel free to subscribe by clicking here.

Context

Let’s say you work in a company and your boss asks you, for the needs of the company, to develop a small application to compress a file. The important feature of this application is compression. At first, it tells you that the application will have to handle two types of files. Zip and gzip files for example. To put it simply, you manage your algorithm in a single file. That is to say, if it is a zip file, we do this, otherwise we process the gzip.

Design Pattern Strategy Context
A compressor class


For the first version, you develop the application with the requested functionality. Your boss is happy with your work. After two months, he comes back to tell you that in reality, at the company level, clients send you files with a type that your application does not take into account (.rar file for example). This application will need to be modified to take into consideration the third file type. You go back to your code, you modify it to manage the third extension. Once again, the application does the job. After some time, the boss now comes back with another problem. He wants the application to now manage two other file extensions in addition to those it already manages. You do what he asks because, after all, he’s the boss. You recompile and redeploy the application so that we continue to use it. As you modify your code, it comes back with another problem. This time, he wants the application to handle mp3, mp4, etc. extensions. And it’s starting to become a total mess. Because all this time, financially speaking, the application is working well but technically it is something else.

In addition, new members have just been added to your team. Working as a team becomes ineffective. Because the members added to your team right after the release and success of your application complained about spending too much time-solving problems. Adding a new feature required you to modify a huge class, creating conflicts in the code produced by other developers. The application becomes more difficult to maintain.

Solution and Architecture

To avoid these hassles (the problems mentioned above), the design pattern strategy gives us a guide to follow to do so.

Using the design pattern strategy, it is possible to define a family of interchangeable algorithms dynamically and encapsulate them, allowing the appropriate algorithm to be used interchangeably depending on the context. That is, he suggests choosing a class that has a particular behavior but executes it in different ways, and dividing its algorithms into separate classes called strategies.

It is essential that the context has an element that maintains a reference to one of the strategies. Instead of taking charge of the task, the context entrusts it to the strategic object associated with it.

The choice of the appropriate algorithm does not depend on the context, it is the client which sends it the strategy which it must use. In reality, the strategies are not very well known to the context; it is the generic interface that allows it to exploit them. Only one method is presented to trigger the algorithm encapsulated inside the chosen strategy.

Thus, the context becomes autonomous to concrete strategies. It is possible to modify or add new algorithms without having to modify the context code or other strategies.

Design Pattern Strategy Solution and Architecture
The architecture of the Design Pattern Strategy

Design Pattern Strategy in Java

Case study

In this case study, we will take the example of an e-commerce platform that must manage several payment methods to allow its customers to pay their invoices. On this platform, we find articles. A user can purchase an item and pay their invoice directly from it using the payment method of their choice (PayPal, Credit Card, bitcoin, etc.). To do this, she thought of a design pattern, in this case, the strategic model. the diagram below presents the architecture of the solution using the design pattern strategy.

Java Example of Design Pattern Strategy
Architecture of the solution using the principle of the design pattern strategy

In this structure, it is possible to classify it into three distinct parts:

  1. The PaymentContext class represents the context.
  2. The MainPaymentClass class represents the customer.
  3. The block of strategies that brings together (the PaymentStrategy interface as well as the concrete strategies PayPalPayment, BitCoinPayment, and CardPayment).

The PaymentContext class maintains a reference to one of the concrete policies and will only communicate with this object through the policy interface. Each time an algorithm is launched, the context requests the execution method of the corresponding strategy object. The context is not aware of how the strategy works or how the algorithm is implemented.

The different concrete strategies, such as PayPalPayment, BitCoinPayment, and CardPayment, use a common interface called PaymentStrategy. In this interface, a pay() method is declared, and used by the context to execute a specific strategy. And the various concrete strategies will implement this interface and each will be able to use its own logic to implement the pay() method at home. Concrete Strategies integrate various versions of algorithms that are used depending on the context.

The Client develops a particular object. Strategy and context. The context presents a setter that gives clients the ability to override the context-related policy during implementation.

Implementation

In this example, the context uses multiple Policies to launch various payment methods.

The Interface Strategy

// Interface
package com.faelma.pattern.strategy;

public interface StrategyPayment {
    void pay();
}

The Strategies

// First Strategy implement the Bitcoin algorithm payment

package com.faelma.pattern.strategy;

public class BitCoinPayment implements StrategyPayment {
    @Override
    public void pay() {
        System.out.println("Payment with Bitcoin has been done successfully");
    }
}

// Second Strategy implement the Credit card algorithm payment

package com.faelma.pattern.strategy;

public class CreditCardPayment implements StrategyPayment {
    @Override
    public void pay() {
        System.out.println("Payment with Credit card has been done successfully");
    }
}

// Third Strategy implement the PayPal algorithm payment

package com.faelma.pattern.strategy;

public class PayPalPayment implements StratagyPayment {
    @Override
    public void pay() {
        System.out.println("Payment with PayPal has been done successfully");
    }
}

The Context

package com.faelma.pattern.strategy;

public class PaymentContext {
    private final StrategyPayment strategyPayment;

    public PaymentContext(StrategyPayment strategyPayment) {
        this.strategyPayment = strategyPayment;
    }

    void executePayment() {
        if (strategyPayment == null) {
            System.err.println("This payment method "+ strategyPayment + " Not found");
            return;
        }
        strategyPayment.pay();
    }
}

The Client

package com.faelma.pattern.strategy;

public class StratagyMain {

    public static void main(String[] args) {
        PaymentContext paymentPaypalContext = new PaymentContext(new PaypalPayment());
        paymentPaypalContext.executePayment();

        PaymentContext paymentCreditCardtContext = new PaymentContext(new CreditCardPayment());
        paymentCreditCardtContext.executePayment();

        PaymentContext paymentBitcoinContext = new PaymentContext(new BitCoinPayment());
        paymentBitcoinContext.executePayment();

        PaymentContext context = new PaymentContext(null);
        context.executePayment();
    }
}

Result

Payment with Paypal has been done successfully
Payment with Credit card has been done successfully
Payment with Bitcoin has been done successfully
This payment method null Not found

Process finished with exit code 0

The full source code is available on GitHub.

Design Pattern Strategy Use Cases

As a design reference, the strategy model is not restricted to a single application domain during software development. The nature of the problem will determine its use. It is ideal for any software requiring great flexibility in solving tasks and problems, by offering options and behavior adjustments.

Here are some common use cases for the Strategy design pattern:

  1. Sorting a list: Let’s say you have a list of objects and you want to be able to sort it by different criteria such as ascending order, descending order, or using another specific sorting algorithm. You can implement a sorting strategy interface, with different strategy classes representing the different sorting algorithms. You can then use a policy object to sort the list according to the desired algorithm.
  2. Shipping cost calculation: In an order management system, you can have different carriers and different shipping cost calculation policies. You can use the Strategy design pattern to encapsulate each compute policy in a separate strategy. So, you can easily change the shipping cost calculation strategy depending on the selected carrier.
  3. File Compression: While compressing files, you may have different compression methods available, such as ZIP compression, RAR compression, etc. You can use the Strategy design pattern to encapsulate each compression method into a separate strategy. This allows the user to choose the desired compression strategy at runtime.
  4. Report Generation: In a reporting system, you can have different report output formats, such as PDF, HTML, CSV, etc. You can use the Strategy design pattern to encapsulate each report format into a separate strategy. So, you can easily generate reports in different formats using the appropriate strategy.
  5. In the standard Java library (Java API) and the Java GUI-Toolkits (AWT, Swing, and SWT), the design pattern strategy is also used, using a layout manager for the development and creation of user interfaces.

Advantages and Disadvantages

Design Pattern Strategy Advantages

– It is possible to interchange the algorithm used inside an object during interpretation or execution.
– We can differentiate the characteristics of the implementation of an algorithm from the code that uses it.
– It is possible to integrate as many new strategies without requiring any changes to the context. Thus respecting one of the SOLID principles, namely the open/closed principle.

Design Pattern Strategy Disadvantages

Despite its advantages, the Strategy pattern also has disadvantages. Software design can be a source of repetition and internal communication problems, due to its more complex configuration.

There is no need to make your program more complex by using the new classes and interfaces that come with setting up the pattern if you only have a few algorithms that don’t differ much.

At the time of implementation, there is an internal relationship between the client and the strategies. The client makes a decision and triggers the concrete strategy using a trigger command. It is necessary to be aware of concrete strategies. Thus, this design pattern should only be employed when changes in strategy and behavior are necessary.

Do you want to know more about “Design Patterns” in general? Take a look at this previous writing by the same author:

———————

We have just started our journey to build a network of professionals to grow even more our free knowledge-sharing community that’ll give you a chance to learn interesting things about topics like cloud computing, software development, and software architectures while keeping the door open to more opportunities.

Does this speak to you? If YES, feel free to Join our Discord Server to stay in touch with the community and be part of independently organized events.

———————

Conclusion

In the field of object-oriented programming, Strategy patterns offer the possibility of improving efficiency by offering personalized solutions. From the design phase, possible future modifications are optimally managed. Generally, this system which emphasizes flexibility and dynamics can be better directed and controlled. It is possible to fix bugs and inconsistencies more quickly thus reducing development costs by using reusable components, especially in complex projects. However, it is important to find the right balance. Frequently, these models are used too conservatively or too often.

Thanks for reading this article. Like, recommend, and share if you enjoyed it. Follow us on Facebook, Twitter, and LinkedIn for more content.

author-avatar

About Faouzi EL Mansour

I am a software engineer with over 3 years of experiences. I am much more passionate about web development and Artificial Intelligence. In my daily life, I use Java with Spring Boot and Angular. We can connect on LinkedIn.