Functional Programming Design Patterns: Part 1 - Strategy Pattern
Tags: codenewbie, functional, programming, designpattern
Published: 2020-11-15 12:52:25


_This post is **Part 1** of a series on utilizing **Design Patterns** in the context of **Functional Programming**. If you are interested in learning more, stay tuned for more on my [DEV page](https://dev.to/qgabe)._

# Introduction
Made ubiquitous by the indispensable book _Design Patterns: Elements of Reusable Object-Oriented Software_ written by the Gang of Four, **Design Patterns** in Software Engineering (SE) are often utilized as battle-tested ways to solve recurrent system design problems in a flexible and reusable way.

<br><img alt="Design Patterns: Elements of Reusable Object-Oriented Software" src="https://images-na.ssl-images-amazon.com/images/I/51szD9HC9pL._SX395_BO1,204,203,200_.jpg" width="400px"/><center><em>The now must-have book in every Software Engineer's bookshelf. [[source](https://images-na.ssl-images-amazon.com/images/I/51szD9HC9pL._SX395_BO1,204,203,200_.jpg)]</em></center>

However, Design Patterns are more often than not, are utilized in an **Object-Oriented Programming** (OOP) fashion. Many patterns include the use of abstract classes, interfaces and other OOP features that do not make sense in the context of **Functional Programming** (FP), where whole systems are composed of functions instead of concrete classes.

Thus, this poses a sort of cognitive mismatch for many engineers who have internalized these OOP patterns and are finding themselves in an environment where FP is growing in popularity.

This post and the subsequent series seeks to provide some instruction and examples on using some of these patterns in the context of FP.

# The _Strategy_ Pattern
The _Strategy_ Pattern from the GoF book is described as a way to vary a _family_ of encapsulated _algorithms_ to make them interchangeable from a runtime _context_. That definition can be a mouthful, so let's break it down.

![Strategy](https://dev-to-uploads.s3.amazonaws.com/i/fvkjhyqtxqvjswkjg33v.png) 

We have a few components here:
  * **Algorithm** - A procedure that takes some value as input, performs some steps on the input, and produces an output.
  * **Strategy** - A common interface implemented by all Algorithms.
  * **Context** - A Run-time environment or a parent process that seeks to utilize a different algorithm given some condition.

<hr>

## Retail Store Example
To make it easier to understand this, let us adapt this pattern in a real-life context:

Suppose we have a **retail store** and we want to introduce a way to implement **different pricing algorithms** to calculate the **total price of a customer's order** depending on the **type of a customer** (_walk-in_ or _online_).

We can first define our pricing algorithms as follows:
### Strategy and Algorithms
```java
interface PricingStrategy {
    public float getTotalPrice(CustomerOrder);
}

class WalkInPricing implements PricingStrategy {
  public float getTotalPrice(CustomerOrder order) {
      // Calculate the price per item in order
      // according to the walk-in pricing
      ...
      return totalPrice;
  }
}

class OnlinePricing implements PricingStrategy {
  public float getTotalPrice(CustomerOrder order) {
      // Calculate the price per item in order
      // according to the online pricing
      ...
      return totalPrice;  
  }
}
```

Following that, we can then introduce the strategy and algorithms to the context, like so:

### Context
```java
PricingStrategy pricing;
...
// First, we decide type of customer and pricing algorithm to use.
switch(customer.type) {
    case "walkIn":
      this.pricing = new WalkInPricing();
      break;
    case "online":
      this.pricing = new OnlinePricing();
      break;
    default:
      throw new IllegalCustomerType("...");
}

// Secondly, we get the calculated total price for the order using the pricing algorithm.
this.totalPrice = this.pricing.getTotalPrice(customer.order);
...
```

This is pretty simple and intuitive!

There are a few benefits to designing the variation this way:
1. We avoid implementing a **single brittle monolithic algorithm** that accounts for all the conditions. Or even implementing the logic in `Context` itself! (e.g. Implementing a `PricingAlgorithm` class that has a lot of if/else and switch statements to check the customer type).
2. We introduce **extensibility** by encapsulating the algorithms separately. If we want to introduce a new pricing algorithm for a new customer type, we simply need to extend the switch statement in `Context` and have the new pricing algorithm implement the `Strategy` interface.

# The Functional Approach

Now that we've established how to use the _Strategy_ Pattern in an OOP fashion, how do we implement the same kind of logic in a FP-friendly way?

Well, quite simply we can leverage the idea of **higher-order functions**, where functions can take in other functions as parameters.

```js
const getMathResult = (mathOperation, arguments) => {
    return mathOperation(arguments);
};
```
<center><em>A simple higher-order function.</em></center>

This allows us to represent a similar abstraction provided by using an interface in OOP!

Let us explore how we can do this:
```ts
const walkInPricing = (orders: CustomerOrder): Number => {
    // Calculate the price per item in order
    // according to the walk-in pricing
    ...
    return totalPrice;
}

const onlinePricing = (orders: CustomerOrder): Number => {
    // Calculate the price per item in order
    // according to the online pricing
    ...
    return totalPrice;      
}


const getTotalPrice =
(pricingStrategy: (CustomerOrder) => Number,
orders: CustomerOrders): Number => {
    return pricingStrategy(orders);
}

...
let pricing;
switch(customer.type) {
    case "walkIn":
      pricing = walkInPricing;
      break;
    case "online":
      pricing = onlinePricing;
      break;
    default:
      throw new IllegalCustomerType("...");
}
getTotalPrice(pricing, orders);
```

As you can see, we simply substitute the Strategy interface with the `getTotalPrice` function which consumes the `pricing` algorithm specified as a parameter and returns us the price for the given function.

This structure allows us to leverage off the same extensibility and encapsulated design that the pattern gives us in the OOP approach! With lesser OOP specific syntax, the code is also shorter and more understandable, which more complex implementations can benefit from.

# What's next
This post is **Part 1** of a series on utilizing **Design Patterns** in the context of **Functional Programming**. If you are interested in learning more about design patterns implementing in the Functional Programming paradigm, stay tuned for more on my [DEV page](https://dev.to/qgabe).