Ruby & The Strategy Pattern

Josh Saint Jacque
Jun 27, 2017 · 4 min read

The Strategy pattern is the next in our examination of design patterns and how they can be leveraged in Ruby. This pattern is useful for varying parts of an algorithm at runtime, similarly to the Template Method pattern. Unlike the Template Method, which uses inheritance to change part of the algorithm, Strategy uses Dependency Injection.

It’s a powerful tool for keeping code maintainable by adhering to the “D” in SOLID, the Dependency Inversion Principle. DIP states that concretions (details) should depend on abstractions, rather than the other way around. By injecting a dependency at runtime we decouple our abstraction from the concrete implementations of its algorithm.

This can be really useful. By passing in our dependencies to a class at runtime, our class doesn’t have to care about what an object is. Instead, it only cares that it responds to a certain message that it wants to send.

When to Consider the Pattern

There are a number of scenarios where the Strategy pattern is worth considering:

Let’s look at an example.

Strategy in Action

Let’s say we’re working on some piece of software that handles logic for a game. This game is in very early development, so the requirements are very clear just yet. All we really know is that it’s a racing game so concepts like drivers and cars will likely make an appearance.

We’ve been handed a use case for a new feature that reads, “given a car, a driver should be able to accelerate up to a chosen speed.” That seems simple enough. Let’s use a sequence diagram to think things through.

Image for post
Image for post

Super simple! A Driver object seems to make sense, as does a Car since that’s the only type of vehicle we’ve been asked to account for. So we quickly write two classes to fulfill this use case.

This works fine; our tests pass, our use case is fulfilled. We commit the changes and move on to other things.

Then one day the product manager comes back with a new requirement. Early user panels indicate customers want a greater variety of vehicles than just cars. Right now, they just want to add motorcycles but the roadmap now envisions boats, planes, trains, and who knows what else.

Now we have a problem. We’ve hard-coded a dependency in our Driver class on a Car object. We need to 1) remove that dependency and 2) support any arbitrary kind of vehicle that can handle the behavior (acceleration, in our simple example).

The Strategy pattern to the rescue. We can fix both issues with one minor change: injecting the dependency instead of hard-coding it.

Now, whenever we call Driver.new we can pass in any kind of object as long as it responds to the accelerate_to message.

Our code can now handle any kind of vehicle and, what’s even better, is completely decoupled from any other object. Future changes are less likely to break this class (e.g., adding new vehicles). The Driver object is so resilient because it can be invoked in any context, and that context is actually what determines any dependencies. Consequently, testing this class is now much easier. You don’t have to setup the universe to be just so in order to get this object to behave.

Trade offs

The Strategy pattern helps you vary behavior of a larger algorithm without using a bunch of conditional, hard-coded dependencies, or type-checking. It’s not without cost, however. Dependencies still exist (objects have to talk to each other to do anything interesting), they’re just invoked by the context at runtime. Doing so may be cleaner and more maintainable in some cases, and messier in others. If it’s going to end up requiring shotgun surgery in the future because you have a change a bunch of different contexts, consider using a wrapping class or a different pattern altogether.

Conclusion

The Strategy pattern is a powerful tool for any developer to have access to. It’s great for decoupling code and keeping objects simple and context-independent. It’s one of the more commonly implemented design patterns, and one you’ll likely find useful in your career.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch

Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore

Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store