Design Patterns Saga: Manta Ray vs Butterfly

Overview of Strategy Design Pattern

Gene Zeiniss
The Startup
8 min readJun 25, 2020

--

Image by Jermaine W from Pixabay

Swimming pools have finally opened, after almost three months of quarantine. I’m not a good swimmer and prefer the sea to the pool. I do enjoy watching people swim in the gym pool, however. It’s like an intricate clock mechanism that I can watch forever. Each swimmer is a necessary detail in this mechanism. Someone’s going faster, someone else is slower. Someone makes frog-kicks with his leg. Someone spits little jets of water, like a whale. And, the most impressive, the one who jumps out of the water like a Manta Ray and dives again. But all of them constantly make their way from one edge of the pool to the other and back again (and all of them in swimming caps and goggles, seemingly anonymous). Tik Tak.

According to google search results, there are four popular swimming strokes — Front Crawl (known as Freestyle, because it dominates races where the choice of swimming style is free, such as triathlons), Backstroke, Breaststroke, and Butterfly (I would describe Butterfly stroke more of a Manta paddle). Is it just me or is there a connection between the Front Crawl and the Butterfly? Caterpillar crawls until it’s a pupa… 🐛 → 🦋 , no? Never mind.

Image from enjoy-swimming.com

I’m using a cheat sheet for beginners, to overview these different swimming strokes. Each stroke description includes body movement, arm movement, leg movement, and breathing. Sounds like a classic example for using inheritance for code reuse, right?

So, what’s the problem?

What’s the problem?

Before you jump to create a swimmer guide, take a look at the description of the movement of each stroke. Just to make it visual, I organized everything into a spreadsheet and highlighted things that caught my attention.

The Freestyle and Backstroke both swim in a horizontal position, but Backstroke swimmers do it on their back (obviously). Breaststroke and Butterfly use a prone position, but in different ways as well. Butterfly’s body executes a wave-like undulation. The same notes on arm movements. Now, take a look at leg movement and breathing. Freestyle has exactly the same flutter kick as Backstroke and same breathing instructions as Butterfly. In Backstroke, there are no special instructions at all, since breathing is not restricted.

Consider the implementation of the swimming guide above. We can override each behavior by concrete swimming stroke classes. Let’s assume that flutter kick is the default leg movement, then whip kick and dolphin kick are overridden behaviors. Butterfly with Manta paddle and Dolphin kick, that’s what I call a naming embarrassment.

So far so good. Now you want to add the additional swimming stroke, let’s call it Pupa (still think about 🐛 → 🦋) that has a 100% dolphin kick. I’m guessing you will add an additional base level (or will just copy the Breaststoke’s leg movement implementation).

Then you will add some additional strokes, heaven forbid, Synchronous Swimming, that has hundreds of positions. From here on it’s a short slide into madness 🤪.

It’s becoming apparent that our previous example suffered from excessive tight-coupling. When code is tightly coupled to a specific solution (or the current model of the problem) it becomes difficult to extend it. The world, for better or worse, is a dynamic place. The problems we already fixed change and our old solutions become irrelevant like yesterday’s news.

The Strategy Design Pattern is an attempt to provide extensibility in a dynamic world that achieves a set goal. The method of doing things may change but the end goal remains the same.

I think that the most important aspect of the Strategy pattern is: the understanding that inheritance is not intended for code reuse (such a chip on your shoulders!). It’s about using composition rather than inheritance. Before we jump into the Strategy Pattern solution, let’s refresh what we know about Composition.

What Do We Know About Composing Objects?

While inheritance is an easy way to achieve a high amount of code reuse, it comes with the cost of tightly coupling the super-class with its sub-classes. Design patterns are instrumental in reducing tight coupling and controlling them. Less coupling in your system means that the system is more flexible and is open to changes. To be honest we need inheritance much less than some object-oriented guides and examples would have us believe.

Whaaa! (you cry), why is there coupling? I can hear the track from “The Game of Thrones” in the background (Pham-pham, pham-pham-pham, pham, pham-pham-pham). My obsession with inheritance. Think about what inheritance does in object-oriented programming. The sub-class that inherits from the super-class will gain knowledge and access to some of the ancestors’ attributes and methods. Well uh, when classes are interdependent, it’s a coupling. When one class knows too much (too much for me to let it live) about the implementation of another class, it’s a tight-coupling. Think about it, if one concern is spread over many classes, it’s become an issue to fix it. Some parts are inherited but cannot be changed — the private scope of the parent. So if you are the descendant of the Targaryens of Valyria you know that at some point you will go mad. It’s part of your inheritance. See?

By Composing objects you can avoid tight-coupling and still gain a high degree of code-reuse. One of Oxford’s definitions of composition is “the action of putting things together; formation or construction”. The Composing Objects principle follows this definition. The overall behavior of a system is derived from the composed sum of the individual objects. An object can aggregate another object to delegate certain tasks to it. Delegation avoids code duplication and provides a lower level of coupling than inheritance. Since the composed objects don’t share attributes or implementations of behaviors, they’re less dependent on each other. They have an arms-length relationship, in other words, they are “avoiding intimacy or close contact” (thanks to Oxford), so changes can be made more easily.

Just to be clear, I’m not saying that inheritance should never be used. You just need to examine the needs of your system in order to determine which design principle is appropriate.

Design patterns, such as the Decorator (that was a topic of the previous chapter) and Strategy (we will overview next) use the Composing Object Principle. Both of these patterns compose concrete classes in order to build more complex objects at one time.

Strategy Pattern

Let’s check the Wikipedia definition:

The strategy pattern (also known as the policy pattern) is a behavioral software design pattern that enables selecting an algorithm at runtime. Instead of implementing a single algorithm directly, code receives run-time instructions as to which in a family of algorithms to use. Strategy lets the algorithm vary independently from clients that use it.

Let’s decompose this 🙃; Strategy is a behavioral pattern. I wrote about design patterns categories in the first chapter of Design Patterns Saga. If you need some overview of behavioral patterns, you can find it there.

Strategy Pattern is particularly useful when you need an ability to achieve a single goal in different ways, selected at run-time. We have algorithms for movements of particular parts of the body. We realize the problem model is too complicated to use a simplistic hierarchical solution in order to share code between different implementations.

There are a few approaches to implement the Strategy Pattern. One approach is to extract the algorithms and inject them into base-class. In other words, we will create strategies for different Swimming Strokes’ behaviors.

Take a look at the data-diagram. The Swimming Stroke now delegates its body, arm and leg movements, and breathing behavior instead of defining these behaviors as methods. The behaviors are injected into an instance of Swimming Stroke, and not hard-coded in the class. This allows us to compose new swimming strokes using different behaviors, or in pattern-speak; use different strategies.

So, let’s look at what that would look like in code.

Strategy Pattern Implementation

First, encapsulate your body movements and breathing behaviors. Let’s take a leg movement as an example. Note the common interface in use here.

Create body and arm movements, and breathing strategies in the same manner (the full code you can find here).

Now, inject the strategies to the abstract Swimming Stroke class.

Next create a concrete swimming strokes definition by injecting the concrete strategies into the parent. This is how Butterfly looks like:

Finally, create a Swimming Guide Service and add Overview Butterfly Stroke method:

Call the overviewButterflyStroke() method and check the logs:

WaveLikeUndulation — The body executes a wave-like undulation, where the chest and the hips move up and down in the water in a specific order.SymmetricalArmMovement — The hands trace an hourglass pattern underwater, moving from an extended forward position to below the chest and then to the hips.DolphinKick — The legs held together and move up and down symmetrically with the feet extended.BreathDuringTheArmRecovery — To breathe, the swimmer turns his head to the side during the arm recovery until the mouth is above the water surface.

That’s all. I have nothing more to add. Well, maybe resume the Butterfly Stroke naming discussion… I’m just putting this out there.

Here is a link to the git project of this post.

--

--

Gene Zeiniss
The Startup

My blog is about wide aspects of programming, from design to code review. Still, I have a predilection for coding, all comes from my unabashed love for Java ☕