What is Strategy Design Pattern

Introduction:

The Strategy Design Pattern is a behavioral pattern that enables the selection of a specific algorithm at runtime from a set of alternative algorithms. This pattern encapsulates the algorithm into a separate class and provides a context class to interact with the algorithm. The context class delegates the request to the algorithm class, and the algorithm class performs the requested operation. This pattern enhances the flexibility and modularity of the code by separating the algorithm logic from the context logic.

In this article, we will discuss the Strategy Design Pattern in detail, its implementation in Java, & C, its advantages, disadvantages, and some use cases.

Implementation in Java:

The Strategy Design Pattern in Java involves the following classes:

1. Context Class: This class contains a reference to the strategy interface and delegates the request to the strategy object.

2. Strategy Interface: This interface defines the method that the algorithm classes must implement.

3. Concrete Strategy Classes: These classes implement the strategy interface and provide a concrete implementation of the algorithm.

Let’s take an example to illustrate the implementation of the Strategy Design Pattern in Java. Consider a shopping cart application that calculates the total price of the items in the cart. The cart can contain items with different pricing policies. The pricing policies can be flat discount, percentage discount, or no discount.

We can implement the Strategy Design Pattern to handle the different pricing policies as follows:

public interface PricingPolicy {
    double calculatePrice(double price);
}

public class FlatDiscountPolicy implements PricingPolicy {
    private double discount;

    public FlatDiscountPolicy(double discount) {
        this.discount = discount;
    }

    public double calculatePrice(double price) {
        return price - discount;
    }
}

public class PercentageDiscountPolicy implements PricingPolicy {
    private double discount;

    public PercentageDiscountPolicy(double discount) {
        this.discount = discount;
    }

    public double calculatePrice(double price) {
        return price - price * discount / 100;
    }
}

public class NoDiscountPolicy implements PricingPolicy {
    public double calculatePrice(double price) {
        return price;
    }
}

public class ShoppingCart {
    private List<Item> items;
    private PricingPolicy pricingPolicy;

    public ShoppingCart(PricingPolicy pricingPolicy) {
        this.items = new ArrayList<>();
        this.pricingPolicy = pricingPolicy;
    }

    public void addItem(Item item) {
        this.items.add(item);
    }

    public void removeItem(Item item) {
        this.items.remove(item);
    }

    public double getTotalPrice() {
        double totalPrice = 0.0;
        for (Item item : this.items) {
            totalPrice += item.getPrice();
        }
        return pricingPolicy.calculatePrice(totalPrice);
    }
}

public class Item {
    private String name;
    private double price;

    public Item(String name, double price) {
        this.name = name;
        this.price = price;
    }

    public double getPrice() {
        return price;
    }
}

In the above example, the PricingPolicy interface defines the calculatePrice() method that the different pricing policies must implement. The FlatDiscountPolicy, PercentageDiscountPolicy, and NoDiscountPolicy classes provide a concrete implementation of the calculatePrice() method.

The ShoppingCart class maintains a reference to the PricingPolicy interface and delegates the request to the pricingPolicy object’s calculatePrice() method. The Item class represents an item in the cart and provides the price of the item.

We can create different pricing policies and pass them to the ShoppingCart object as follows:

ShoppingCart cart = new ShoppingCart(new FlatDiscountPolicy(10.0));
cart.addItem(new Item("Item 1", 100.0));
cart.addItem(new Item("Item 2", 200.0));
double totalPrice = cart.getTotalPrice();
System.out.println("Total Price: " + totalPrice);

The above code creates a shopping cart object with a FlatDiscountPolicy pricing policy with a discount of 10.0. Two items are added to the cart, and the total price is calculated using the getTotalPrice() method. The output of the above code is:

Total Price: 290.0

Here, the total price of the two items is 300.0, but a discount of 10.0 is applied, and the final price is 290.0.

Implementation in C:

The Strategy Design Pattern in C can be implemented using function pointers. We can define a function pointer that points to the algorithm function, and we can pass the function pointer to the context function.

Let’s take the same shopping cart example and implement the Strategy Design Pattern in C:

#include <stdio.h>
#include <stdlib.h>

typedef struct {
    char *name;
    double price;
} Item;

typedef double (*PricingPolicy)(double);

double flatDiscountPolicy(double price, double discount) {
    return price - discount;
}

double percentageDiscountPolicy(double price, double discount) {
    return price - price * discount / 100;
}

double noDiscountPolicy(double price, double discount) {
    return price;
}

typedef struct {
    Item **items;
    int itemCount;
    PricingPolicy pricingPolicy;
} ShoppingCart;

ShoppingCart* newShoppingCart(PricingPolicy pricingPolicy) {
    ShoppingCart *cart = (ShoppingCart*) malloc(sizeof(ShoppingCart));
    cart->items = (Item**) malloc(sizeof(Item*) * 10);
    cart->itemCount = 0;
    cart->pricingPolicy = pricingPolicy;
    return cart;
}

void addItem(ShoppingCart *cart, Item *item) {
    cart->items[cart->itemCount++] = item;
}

void removeItem(ShoppingCart *cart, Item *item) {
    int i;
    for (i = 0; i < cart->itemCount; i++) {
        if (cart->items[i] == item) {
            break;
        }
    }
    for (; i < cart->itemCount - 1; i++) {
        cart->items[i] = cart->items[i + 1];
    }
    cart->itemCount--;
}

double getTotalPrice(ShoppingCart *cart) {
    double totalPrice = 0.0;
    int i;
    for (i = 0; i < cart->itemCount; i++) {
        totalPrice += cart->items[i]->price;
    }
    return cart->pricingPolicy(totalPrice, 10.0);
}

int main() {
    ShoppingCart *cart = newShoppingCart(flatDiscountPolicy);
    addItem(cart, &(Item){"Item 1", 100.0});
    addItem(cart, &(Item){"Item 2", 200.0});
    double totalPrice = getTotalPrice(cart);
    printf("Total Price: %f\n", totalPrice);
    return 0;
}

In the above code, we have defined the PricingPolicy function pointer that points to the algorithm function. The flatDiscountPolicy(), percentageDiscountPolicy(), and noDiscountPolicy() functions provide a concrete implementation of the algorithm function.

The ShoppingCart struct maintains a reference to the function pointer and delegates the request to the function pointed by the pricingPolicy function pointer.

We can create different pricing policies and pass them to the ShoppingCart object as follows:

ShoppingCart *cart = newShoppingCart(flatDiscountPolicy);
addItem(cart, &amp;(Item){"Item 1", 100.0});
addItem(cart, &amp;(Item){"Item 2", 200.0});
double totalPrice = getTotalPrice(cart);
printf("Total Price: %f\n", totalPrice);

The output of the above code is:

Total Price: 290.0

Advantages and Disadvantages of Strategy Design Pattern:

Advantages:

1. Easy to change behavior: The Strategy Design Pattern separates the behavior of an object from its implementation. This makes it easy to change the behavior of an object without affecting its implementation.

2. Improved code readability and maintainability: The use of a Strategy Design Pattern improves code readability and maintainability by breaking down complex algorithms into smaller, manageable components.

3. Encourages code reuse: The Strategy Design Pattern encourages code reuse by allowing the same algorithm to be used in different contexts.

4. Easy to test: The Strategy Design Pattern makes it easy to test individual algorithms separately.

5. Open-closed principle: The Strategy Design Pattern follows the open-closed principle, which means that the code is open for extension and closed for modification.

Disadvantages:

1. Increased complexity: The use of the Strategy Design Pattern can lead to increased complexity in the code, as it involves creating multiple classes and interfaces.

2. Increased memory usage: The use of the Strategy Design Pattern can lead to increased memory usage, as it involves creating multiple objects.

3. Increased development time: The use of the Strategy Design Pattern can lead to increased development time, as it involves creating multiple classes and interfaces.

4. Not suitable for small projects: The Strategy Design Pattern may not be suitable for small projects, as the added complexity may outweigh the benefits.

Conclusion:

The Strategy Design Pattern is a powerful design pattern that allows the behavior of an object to be changed at runtime without affecting its implementation. It separates the behavior of an object from its implementation, making it easy to change the behavior of an object without affecting its implementation. The Strategy Design Pattern improves code readability and maintainability, encourages code reuse, and makes it easy to test individual algorithms separately. However, it can also lead to increased complexity, increased memory usage, and increased development time. It may not be suitable for small projects, as the added complexity may outweigh the benefits.

What is Strategy Design Pattern

Published on 28-Jun-2024 22:01:00

You may also like this!