DEV Community

loading...

Design Patterns - Strategy Pattern in JavaScript

Carlos Caballero
I'm PhD. in Computer Science from Málaga, Spain. Currently, I am teaching developers and degree/master computer science how to be experts in web technologies and computer science.
Updated on ・4 min read

There are 23 classical design patterns which was described in the original book,
Design Patterns: Elements of Reusable Object-Oriented Software. The patterns provides a solution to a particular problem which is repeated in the software
development.



In this article, I’m going to describe the Strategy Pattern how it works,
how and when should be apply. This pattern is known as Policy in other
context.

Strategy Pattern: Basic Idea

The strategy pattern is a behavioral design pattern that enables selecting an
algorithm at runtime — Wikipedia

Define a family of algorithms, encapsulate each one, and make them
interchangeable. Strategy lets the algorithm vary independently from clients
that use it — Design Patterns: Elements of Reusable Object-Oriented Software

The main feature of this pattern is that the client have a set of algorithms in
which a specific algorithm will be selected for use during runtime. This
algorithms are interchangeable between them.

The following code show the classical problem in which you need selected a
concrete algorithm in your app. In this code, you use the switch control
structure of any programming language.

However, it can be more flexible using the Strategy Pattern which will be
the following structure:

The UML’s diagram of this pattern is the following:

Each strategy is represented using a concrete object. So, the client/context
contains a Strategy object (concreteStrategyA, concreteStrategyB,...) which
implements the in interface Strategy. The key of interchange between strategy
consists in implement a method in context which change the strategy, for
example, setStrategy.

Strategy Pattern: When To Use

  1. The problem which resolve Strategy Pattern is when you need use several algorithms which have different variations. In that moment, you need create a concrete class to implement your algorithm (which can consists in a or some functions).
  2. Another interesting moment in which you detect that need this pattern is when there are conditional statements around a several algorithm which are related between them.
  3. Finally you must to use this pattern when most of your classes have related behaviours.

Strategy Pattern: Advantages

The Strategy Pattern have several advantages which can be summary in the
following points:

  • It’s easy switching between different algorithms (strategies) in runtime because you’re using polymorphism using the interfaces.
  • Clean code because you avoid conditional-infested code (not complex).
  • More clean code because you separate the concerns into classes (a class to each strategy).

Strategy pattern: A basic implementation using JavaScript

Now, I’m going to show you how you can implement this pattern using JavaScript,
you must remember that Javascript lacks interfaces. So, you need programming a
class called StrategyManager which is used as the interfaces:

This class contains a private attribute called _strategy which represents the
strategy that will be used in this moment. The method doAction is the method
which will be implement in each concrete Strategy. The Strategy pattern differ
from the UML in JavaScript due to lack of OOP features in the language.

The implementation of each concrete Strategy is the following:

Note that the concrete method doAction is implemented in each concrete
strategy.

Finally, the context/client must contains the StrategyManager (or strategy
interface is the language is OO) to use the concrete strategy:

Strategy pattern: A set of strategies using JavaScript

In the following implementation, our StrategyManager can be more complex and
contains a list of algorithms. In this case, you can change the attribute
_strategy instead of an array called _strategies.

Finally, you can add new strategies in our list of strategies using the method
addStrategy. The Strategy class have two attributes: 1) Strategy’s name; 2)
Algorithm (called handler). The method doAction is the used to invoke the
concrete algorithm.

Finally, the client/context code where we use the concrete strategy is the
following:

The first part is create concrete strategies (which can be construct using the
Singleton pattern and the Factory pattern) and added in our
strategyManager (which could be our interface). The next part of the client
is selected the strategy to use, this strategy can be selected using a GUI
or CLI from our app.

Finally, you can note that if a unsupported strategy is selected the system
return an error. This can be used when you want provide a premium algorithm to
your system.

Conclusion

Strategy Pattern is a pattern which can avoid complex in your code when need
selected a concrete algorithm. In this post you can obtained a simple
implementation using the language JavaScript which lacks interfaces. In the case
that you use a programming language which has interface you can follow the
pattern’s UML.

The most important is not implement the pattern as I’ve shown you but you need
know what’s the problem which the pattern resolve and why you must use because
the implementation will be different depends of the programming language.



Hi! My name is Carlos Caballero and I’m PhD. in Computer Science from Málaga,
Spain. Teaching developers and degree/master computer science how to be experts

Discussion (10)

Collapse
jessekphillips profile image
Jesse Phillips

I don't see the original switch statement going away here. By the end of it all you had a list of strategies and a need to determine which one to use, in the case of the final example you executed all strategies which easily could have been done without the switch statement.

Collapse
askerovtamerlan profile image
askerovtamerlan

code below switch statement maybe alternative high-abstract implementation of switch

Collapse
carlillo profile image
Carlos Caballero Author

Perfect!

Thanks.

Collapse
suchcodemuchwow profile image
batuxd

Pretty tiring, boring, unnecessary fancy words for js world.

const strategyA = {
  run : function () {} 
}
...

const strategies = {
 strategyA,
 strategyB,
 ...
}

// below string should be a variable to make it more dynamic. 
// And can be wrapped with try/catch if not exist will throw error
strategies['strategyA'].run()
Enter fullscreen mode Exit fullscreen mode
Collapse
carlillo profile image
Carlos Caballero Author

Thanks! 🙃

Collapse
onexdata profile image
Nick Steele • Edited

This looks like it only covers older object-oriented style strategy implementations. This doesn't really do the strategy pattern justice in 2020.

Here is a set of functions on an object, and each object has a process functor that does something different. This object is the core of an analytics engine and replaces many hundreds of lines of code and is very extensible:

const events = {
'heartBeat': { id: 0, process: (e) => ({}) },
'mediatimeupdate': { id: 1, ignore: true, process: (e) => e },
'mediaplay': { id: 8, process: (e) => ({ t: e.detail.plyr.currentTime }) },
'mediaplaying': { id: 9, process: (e) => ({ t: e.detail.plyr.currentTime }) },
'touch': { id: 13, update: 'lookingAt', process: (e) => ({ x: e.x, y: e.y }) },
'focus': { id: 14, update: 'lookingAt', process: (e) => ({ x: e.x, y: e.y }) },
'cartAdd': { id: 19, process: (e) => ({ p: e.id }) },
'cartUpdateQty': { id: 20, process: (e) => ({ p: e.thing.id, q: e.qty }) },
'cartClear': { id: 21, process: (e) => ({}) },
}

Now that you have an object of strategies, you create a 1-line dispatcher for the aspect of event processing...

// Here is the actual "strategy" pattern in this design, the way of calling things based on what is being asked for, the "switchboard" that handles routing to different code based on needs...
const $event = (name, payload, stream = defaultStream) => stream(event[name].process(payload))

Now you can pass in any browser or custom event, and it will process it and pull out only the parts you're looking for, and pass that into any stream you're looking for...

this.$event('cartAdd', thing)

...all this was done with the absolute minimum amount of code possible, and it's incredibly powerful, pushing all the code into a single object of functions, and the dispatches become join points on a cross-cutting concern of "events", and events can contain any payload; their processors are all defined in the same place. Every time you see an $event call in your code, you know you are simply dispatching the event itself. Nothing left to do.

This type of use of the strategy pattern elevates your code from OOP to AOP and cuts your LOC drastically and makes things much easier to understand with zero repetition.

Collapse
blixit profile image
Blixit

I think there's some misunderstanding about the strategy design pattern which takes advantages from dependency injection and algorithm detection at runtime based on the use case.

// class to use as 'interface' in your dependency injection
class StrategyA {
doAction() {...}
}

// someStrategy can be string (will require a mapping) or class based on your architecture
function myMethod(...) {
// someStrategy, otherArgs: can be injected as parameters
// or come from the current scope
const dynamicAlgorithm = resolveStrategy(someStrategy, otherArgs);
dynamicAlgorithm.doAction();
}

Collapse
rmohcie profile image
MoroChev

Thanks a lot Mr Carlos that's really helpful

Collapse
askerovtamerlan profile image
askerovtamerlan

Maybe you know something about implementation of reactivity across strategy design pattern? i'm looking information to create craiglist-mimic-site.

Collapse
estebanappdirect profile image
estebanappdirect • Edited

Hi, I got this error "ReferenceError: Engine is not defined" may you can help me? thanks
dev-to-uploads.s3.amazonaws.com/i/...