DEV Community

Cover image for Pop culture design patterns: creational
MeStrak
MeStrak

Posted on • Originally published at mestrak.com

Pop culture design patterns: creational

During a recent interview I asked the candidate about their understanding of design patterns. I was impressed not only with their honesty, telling me they only had basic knowledge, but also with their description of the Singleton pattern:

It's like Highlander … there can be only one.

Since then I discovered that there are already some memes floating around with the same joke, but it made me chuckle anyway. It got me thinking that perhaps there is something in the idea of using pop culture references to remember the fundamental goals of design patterns.

This series is my attempt to choose some good references. It's not to be taken too seriously, and I won't provide in depth explanations of each pattern as there are already amazing sites for this like https://refactoring.guru.

Let's try creational patterns first. Here goes …

Singleton: Highlander - there can be only one

Highlander movie poster

Image sourced from: https://www.vintagemovieposters.co.uk/

Singleton ensures that only one instance of the class which implements it can exist. Global access to that object can be used within state management applications (think Redux).

If you haven't seen The Highlander, you're missing out. I love it, even though it's 80s cheese. Immortals battle it out to be the only immortal, because just like the Singleton pattern 'THERE CAN BE ONLY ONE!'.

Other similarities between Singleton and The Highlander:

  • They're both classics, and both much criticised. I'm not afraid to say that I love both of them - I can still remember my first time implementing a Singleton.
  • In The Highlander, after beheading another immortal, all knowledge that person has obtained during their lifetime is transferred to the surviving immortal in a process called The Quickening. One of the criticisms of Singleton is that it can be used as a global store for everything, resulting in separate components of an application knowing too much about each other.

Builder: Five Guys

Five Guys burger, fries and milkshake

Image sourced from: https://www.timeout.com/

The goal of the Builder pattern is to construct complex objects, and allow you to create variations on those objects using the same code.

A frequently used analogy for this pattern is assembling a meal in a fast food restaurant. My somewhat limited imagination allowed me to think of Five Guys. Think of making a burger as a complex task - implement the Builder pattern to call:

AddPickles()
AddBacon()
AddCheese()
AddKetchup()
Enter fullscreen mode Exit fullscreen mode

Obviously if those are your only choices of Five Guys burger toppings something has gone wrong, but hopefully you get the idea.

Builder also has an optional implementation of a Director, further abstracting the implementation and simplifying things for the client. This is like your Five Guys cashier who takes your order for a burger all the way, and a crazy milkshake with 11 mixins, and then sends all required instructions to the builder team who assemble and deliver your meal.

Prototype: Futurama S6E17 - Benderama

Bender from Futurama with his clones on a triple bike

Image sourced from: https://www.assignmentx.com/

The Prototype pattern is used to remove complexity from copying objects. Objects that implement the Prototype pattern know how to clone themselves, so code that needs to make a copy does not need to know the complexity of the class.

In Benderama, Bender makes clones of himself. Unfortunately each clone is smaller than the previous one and when they reach molecular level they nearly destroy the world. Obviously knowing that detail this analogy falls down entirely.

Factory Method: The Pepsi Challenge

Image description

Image sourced from https://abcnews.go.com/

Factory Method provides a way for a class to create similar objects, but to leave the individual subclasses to use their own logic. This is done by defining an interface implemented by all subclasses so individual objects can be created using common methods, but without knowing the details of what's inside.

First of all, in case you don't know what it is, the Pepsi Challenge is a marketing campaign from the 1980s where shoppers would do a blind tasting of Coke and Pepsi and say which one they preferred.

Why is Factory Method similar to the Pepsi Challenge? Think of an abstract class called SoftDrink which provides a creational method.

CreateDrink()
Enter fullscreen mode Exit fullscreen mode

And an interface implemented by every soft drink providing the following common methods:

FillBottle()
OpenBottle()
PourDrink()
DrinkCola()
Enter fullscreen mode Exit fullscreen mode

This is Factory Method! The creational logic of each drink is the secret recipe closely guarded by Coke or Pepsi. When the consumer takes the challenge, they call the DrinkCola() function but they do not know if they are doing that for Coke or Pepsi, thanks to the Factory Method which hides that complexity (in the form of a big yellow box).

Using this approach, Pepsi could add as many drinks as they want to into the challenge. They don't really need to do that though, as instead through shameless capitalism the two companies have successfully wiped out or bought out most other competition.

One drawback of the Factory Method is that requires implementation of many subclasses. This can make quite a simple concept harder to understand than intended when actually implemented, just like my attempt to use the Pepsi Challenge to explain this pattern.

Abstract Factory: IKEA

Image description

Image sourced from https://about.ikea.com/

You may guess from the name that this one adds a layer of abstraction to the Factory Method. It is used for creating groups of related objects (a family). The Abstract Factory class holds a bunch of abstract creation methods which know how to create instances of the objects. Concrete factories will then be called to actually create the object.

Think of each family like a set of matching furniture from Ikea. The furniture family might contain a chair, sofa and a table. Different style chairs would have the same chair interface, the create() method would implement the style of that chair's given family. The factory for a given family will call the specific create() methods to create each furniture type with the correct style matching the family.

I'm sorry to say that I had a lack of imagination for this one, and the chosen analogy is the same as several other examples online. One of those is the excellently written article on https://refactoring.guru/ which has a great explanation. I recommend that you spend some time reading that, and hopefully the Ikea link will start to stick.


And there you have it, hopefully some memorable references for Singleton, Builder, Prototype Factory and Abstract Factory creational design patterns.

Look out for further posts in this series where I will try to do the same for structural and behavioural patterns.

Fin.

Top comments (2)

Collapse
 
dmahely profile image
Doaa Mahely

I love these analogies! I wish I had seen them when I was learning design patterns for the first time 😆

Collapse
 
oggy2378 profile image
Oggy

class Solution {
public int my###(String s) {

    // Initialize variables
    StringBuilder str = new StringBuilder();
    int sign = 1;
    boolean numberStarted = false;  // Flag to track if number parsing has started

    for (int i = 0; i < s.length(); i++) {
        char ch = s.charAt(i);

        // Skip leading spaces
        if (ch == ' ' && !numberStarted) {
            continue;
        }

        // Handle sign if encountered before digits
        if ((ch == '-' || ch == '+') && !numberStarted) {
            sign = (ch == '-') ? -1 : 1;
            numberStarted = true;
        }
        // Append digits to the string
        else if (ch >= '0' && ch <= '9') {
            str.append(ch);
            numberStarted = true;  // Digits encountered, number parsing has started
        }
        // Stop processing when a non-numeric character is encountered after number start
        else {
            break;
        }
    }

    // If no digits were found, return 0
    if (str.length() == 0) {
        return 0;
    }

    // Convert the number string to integer and handle overflow
    String numberStr = str.toString();
    long ans = 0;
    try {
        ans = Long.parseLong(numberStr);  // Convert StringBuilder to string
    } catch (NumberFormatException e) {
        return 0;  // Return 0 if parsing fails
    }

    // Apply sign and handle overflow
    ans = sign * ans;
    if (ans > Integer.MAX_VALUE) {
        return Integer.MAX_VALUE;
    }
    if (ans < Integer.MIN_VALUE) {
        return Integer.MIN_VALUE;
    }

    return (int) ans;
}
Enter fullscreen mode Exit fullscreen mode

}