Strategy Design Pattern, Author: Majid Ahmaditabar
You can solve the Open–closed principle (OCP) problem by applying the Strategy pattern.

Strategy Design Pattern

Majid Ahmaditabar
4 min readMay 11, 2021

--

Strategy is a behavioral design pattern that lets you define a family of algorithms, put each of them into a separate class, and make their objects interchangeable.One of the dominant strategies of object-oriented design is the “open-closed principle”.

What is Strategy?

The Strategy pattern suggests that you take a class that does something specific in a lot of different ways and extract all of these algorithms into separate classes called strategies.

The original class, called context, must have a field for storing a reference to one of the strategies. The context delegates the work to a linked strategy object instead of executing it on its own.

The context isn’t responsible for selecting an appropriate algorithm for the job. Instead, the client passes the desired strategy to the context. In fact, the context doesn’t know much about strategies. It works with all strategies through the same generic interface, which only exposes a single method for triggering the algorithm encapsulated within the selected strategy.

This way the context becomes independent of concrete strategies, so you can add new algorithms or modify existing ones without changing the code of the context or other strategies.

Strategy is a behavioral design pattern that lets you define a family of algorithms, put each of them into a separate class, and make their objects interchangeable.

  • Use the Strategy pattern when you want to use different variants of an algorithm within an object and be able to switch from one algorithm to another during runtime.
  • Use the Strategy when you have a lot of similar classes that only differ in the way they execute some behavior.
  • Use the pattern to isolate the business logic of a class from the implementation details of algorithms that may not be as important in the context of that logic.
  • Use the pattern when your class has a massive conditional operator that switches between different variants of the same algorithm.

Implement

  1. In the context class, identify an algorithm that’s prone to frequent changes. It may also be a massive conditional that selects and executes a variant of the same algorithm at runtime.
  2. Declare the strategy interface common to all variants of the algorithm.
  3. One by one, extract all algorithms into their own classes. They should all implement the strategy interface.
  4. In the context class, add a field for storing a reference to a strategy object. Provide a setter for replacing values of that field. The context should work with the strategy object only via the strategy interface. The context may define an interface which lets the strategy access its data.
  5. Clients of the context must associate it with a suitable strategy that matches the way they expect the context to perform its primary job.

Problem: Online Store Shipping

Our Online Store has a shipping system to deliver orders to their clients; at this time our store has one type shipping called “ground”.

class Order{
get_shipping_cost(shipping_type){
if(shipping_type == "ground"){
return "ground cost"
}
}
}
order = new order()
display -> order.get_shipping_cost("ground")

what will happen if we add new shipping type (for example “air”) to our online store?

class Order{

get_shipping_cost(shipping_type){
if(shipping_type == "ground"){
return "ground cost"
}
if(shipping_type == "air"){
return "air cost"
}
}
}
order = new order()
display -> order.get_shipping_cost("air")

this code is out of Open–closed principle (OCP) if we have another shipping type again our class is not close and We have not followed SOLID principles.

Solution

class ground_shipping {
get_cost() {
return "ground cost"
}
}
// new shipping method
class air_shipping {
get_cost() {
return "air cost"
}
}
class Order {
display_orders() {}
get_shipping_cost(shipping_type) {
return shipping_type.get_cost()
}
}
order = new Order()
display -> order.get_shipping_cost(new air_shipping())

As you can see, The Order Class is more clean and simple. It is also easier to develop and implement it.and when we add new shipping method it doesn’t need to change Order Class we just define new shipping Class.

Problem: Navigation App

in our navigation App users can find their path and our Application at the moment has an algorithm that calculate navigation by car.

class Navigation{
calculate_navigation(navigation_type){
if(navigation == "car"){
return "run algorithm"
}
}
}
navigation = new Navigation()
display -> navigation.calculate_navigation("car")

Again! this code is out of Open–closed principle (OCP) if we have another navigation type (for example bicycle ) our class is not close and We have not followed SOLID principles.

Solution

class car {
get_navigation() {
return "run algorithm"
}
}
// new navigation method
class bicycle{
get_navigation() {
return "run algorithm"
}
}
class Navigation {
calculate_navigation(navigation_type) {
return navigation_type.get_navigation()
}
}
navigation = new Navigation()
display -> navigation.calculate_navigation(new bicycle())

Pros

You can swap algorithms used inside an object at runtime.

You can isolate the implementation details of an algorithm from the code that uses it.

You can replace inheritance with composition.

Open/Closed Principle. You can introduce new strategies with- out having to change the context.

Cons

If you only have a couple of algorithms and they rarely change, there’s no real reason to overcomplicate the program with new classes and interfaces that come along with the pattern.

Clients must be aware of the differences between strategies to be able to select a proper one.

A lot of modern programming languages have functional type support that lets you implement different versions of an algorithm inside a set of anonymous functions. Then you could use these functions exactly as you’d have used the strategy objects, but without bloating your code with extra classes and interfaces.

References

--

--