Cushing Design Patterns! — Unnecessary Patterns.

Posted on Sep 30, 2019

image

This is the part-II in the continuation of the “Crushing Design Patterns” series (Part-I) where we debunk the idea of having to use the design patterns to design the system.

Intro

They are either just so natural that we have been using them unconsciously or there are better ways in which we don’t have to focus on ceremoniously writing them.Here we go.

1. Builder Pattern

The intent of the Builder design pattern is to separate the construction of a complex object from its representation.> — Wikipedia

Meaning in plain english: A way to create objects with a flexibility to use any number of parameters for its creation.

Question: what is wrong with the constructors?

Actual video of me deciding which parameters to put in constructors

Counter question: How many would you make? To answer that, I’ll have show off my high school mathematics:

If there are n optional parameters/fields, there will be 2^n possible combinations of them, that means we’ll have to create those many constructors.

Turns out it will be 64 for our 6 optional veggies. Oh God, Java will make me die unhealthy!

Here comes the Builder pattern for our rescue,

But hey, this is 2019 and remember, we don’t need to do it like this! Behold, Java has a saviour now, lombok! Let’s rewrite our lombok-y Sandwich class:

That is it! Heck, we didn’t even need write the getters and setters ourselves, lombok does it all for you ! How do we use it, if you ask. Simple:

Pro Tip: If you are a Java dev, you should definitely check out the Project Lombok, it offer dozens of cool modern features with simple annotations. All the lombok annotated code simply de-sugars at the compile time into the ugly Java we don’t wanna write!

Verdict: Builder Pattern is unnecessary in Java due to lombok! Some languages provide features like named and default arguments (Scala, Clojure, Python etc) making the object building easier.

2. Iterator Pattern

Theiterator pattern is a design pattern in which an iterator is used to traverse a container and access the container’s elements. The iterator pattern decouples algorithms from containers.> — Wikipedia

Meaning: It’s a pattern where an abstract container providing a next() method and in some cases hasNext() method as well.

{{ video src=“https://c.tenor.com/H1P0_7Aq8vMAAAPo/next-britney-spears.mp4" autoPlay=true loop=true id=“next-britney-spears.mp4” }}

At this point, if you are a programmer, your brain should be screaming right now. We already have those in every mainstream programming language!!.

  • Java has Iterator<T< interface.
  • Python objects provides next() method.
  • Scala and other functional languages provide sequences and lazy sequences.

3. Command Pattern

Here, object is used to encapsulate all information needed to perform an action or trigger an event at a later time.> — Wikipedia

Meaning: Every command implementation does what it is meant for!

Usage:

You got the point right! Now, I want to you to pay attention and see that “we only care about the encapsulated execute() method”. So, in a nutshell, the Command pattern is just a function/method!

This becomes very intuitive with Java-8 lambdas, we don’t need to create LoginCommand and LogoutCommand wrapper implementations of the Command interface:

BTW, this is very easy in functional languages, let’s take Scala for example:

4. Strategy Pattern

Strategy pattern (also known as the policy pattern) 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.> — Wikipedia

Meaning: Injecting the algorithm/strategy for some computation at runtime.

For example, suppose we are running a country named LaLaLand and are running out of cash. What would be the best way to fill up our stash?

We start making a taxing strategy, let’s tax a quarter of the income of everybody.

# quarter-taxing-strategy:
tax = user.income / 4

But , when we think about the good people running a kitten orphanage NGO, we feel bad for them. Also, we want to tax more the black money holders now. We need more strategies!

# non-profit-taxing-strategy:
tax = 0
# half-taxing-strategy:
tax = user.income / 2

Here, the algorithm is the taxing strategy to compute the taxes from users. More strategies mean, more algorithms (functions). Let’s start with good old Java way:

For every new strategy, we need to create another implementation class! Usage:

Smart ones among you might already have guessed that we don’t need the wrapper implementation classes, we just need functions as strategies and pass them around arguments!

Let’s do it in functional way (no need to create multiple implementations of Strategy interface):

In functional languages (Scala):

Conclusion

We have discussed 4 pattern in this post: Builder, Iterator, Command and Strategy. Each one can be used without writing any pattern, simply by just intuitively using language features (even in Java). Each pattern has been right in front of us hiding in the language!

In summary:

  1. Builder — Lombok’s Builder annotation in Java, named and default parameters in other languages (Scala, Clojure, Python etc).
  2. Iterator — Readily available interfaces/abstractions in many languages.
  3. Command — Just pure functions.
  4. Strategy — passing functions as strategy at runtime.