Originally I posted this on dev.to, that’s why this content was released 4 years earlier than the rest of the website. Series is here
I’m sure most of us are familiar with at least some of the patterns laid out by the “Gang of Four” in the book Design Patterns: Elements of Reusable Object-Oriented Software
. These patterns were incredibly helpful in OO languages because they provided answers to problems that these languages desperately needed.
OO languages were built around the idea of classes instead of functions, so while objects were often treated as first class citizens, functions were not. This inability to manipulate functions to their fullest extent left gaps in expressiveness that these patterns filled.
As time moves on, however, languages are learning from each other, and a lot of functional practices are moving to OO languages. As this happens, the patterns that answered these gaps in expression will no longer be needed.
In this series, I’ll be going over patterns that are either already obsolete or are in the process of becoming so.
Command Pattern Link to heading
The goal of this pattern was to encapsulate information about how to execute a method in a Command
. A Command
is an interface with a single abstract method usually called execute
of type () -> ()
. This method actually runs the method the Command is “wrapping”.
The benefits of Commands were:
- The ability to be passed around as a first class value, e.g storing it in lists, passing it to other functions for execution based on certain conditions, etc.
- The separation of passing in parameters (specifically into the constructor) and execution of the function.
- The ability to group commands based on a common interface.
- The encapsulation of information about executing a function to reduce repetition at call sites, and the separation of business logic from other concerns like presentation or data storage.
However, all these benefits can be accomplished via other means. Not only this, but these other means are often more semantically expressive.
First, we’ll go over an example of implementing the command pattern in Java 7. This example is mostly from GeeksforGeeks: Command Pattern. A similar example also exists on Wikipedia: Command Pattern. Afterwards, we’ll refactor out the command pattern using Java 8 features.
Java 7 Code Link to heading
Here are our Entities
:
|
|
|
|
|
|
Looking at the above, you might be curious what IO
is. Well, it’s just a simple dependency that I defined in Boundary
so as to not couple my code with PrintStream
or more specifically System.out
.
The code is actually relatively simple:
|
|
and the only implementation that exists in this app is this one:
|
|
And finally, our Commands
:
|
|
|
|
|
|
|
|
|
|
This is the code we can use to see the above functionality:
|
|
Java 7 Explanation Link to heading
So far so good, but there’s definitely a lot of overhead here. There is noticeable repetition, and that repetition impedes on the expressiveness of the code.
The main form of repetition is in this kind of code (across all the Command
s):
|
|
I like to call this kind of class a glorified function. The function would be typed as SomeType -> ()
, i.e it takes a SomeType and returns nothing.
It’s “glorified” in the context of Java because it has some capabilities that normal functions do not have. You have the ability to pass in the parameter at a different time from execution, and pass around this partially applied function as a first class value.
In this case, the parameter being passed into the constructor of any Command is simply the corresponding entity (receiver) and nothing else. This actually means in our rewrite, we won’t have to worry about higher order functions, because that entity is implicitly passed around to instance methods of said entity.
Before we dive more into the details of the rewrite though, lets actually look at the Java 8 code.
Java 8 Code Link to heading
Entities:
|
|
|
|
|
|
IO:
|
|
|
|
Main:
|
|
Java 8 Explanation Link to heading
So while Stereo
is a tad longer, you probably noticed that an entire, relatively large, section is missing! Commands
are entirely gone, yet we still have code that hits all the original benefits enumerated at the top of this post. I’ll go over those one by one, and explain how we’re still achieving the benefits of the Command pattern without using Commands at all.
1
. The ability to be passed around as a first class value, e.g storing it in lists, passing it to other functions for execution based on certain conditions, etc.
So while Java lacks first class functions, it does have a Function
class, as well as other similar Functional Interfaces that can be implemented by lambdas or method references. And this Functional Interface is first class. When we construct a Runnable
with light::on
, we’re passing a reference of that method to setCommand
, just like how we passed a reference of the various Command
s in Java 7.
2
. The separation of passing in parameters (specifically into the constructor) and execution of the function.
This is actually something I alluded to earlier, and we didn’t do this specifically because we didn’t need to here. The only thing we were passing into the Command
constructors were the entities they were accessing (only one for any given Command
).
This is easily possible though. If we needed parameters to be passed in at the time of setCommand
, we could do it by currying the functions that required the parameters (i.e returning a possibly nested Functional Interface from a method like onWithCD
or off
).
As a super simple example of currying, here’s curried addition, note that the type is complex but the implementation is simple, so this is something more type inference could simplify in the future:
|
|
3
. The ability to group commands based on a common interface, usually literally calledCommand
.
This common interface in Java 8 is those FunctionalInterface
s (Runnable, Function, BiFunction, Predicate, etc.). The interface with the same type is Runnable
, which is why we used it in the Java 8 version.
In languages with first class functions, it’s simply functions.
4
. The encapsulation of information about executing a function to reduce repetition at call sites, and the separation of business logic from other concerns like presentation or data storage.
The repetition is still reduced at the call site, because we still have the logic for that command that exists inside of a method. The separation is also achieved, because the business logic still lies with the entity and not inside the presentation layer.
As a bonus, the caller in our presentation layer won’t be tempted to use the methods that used to be public on the entities before, because those are private now. The only reason they were public before was because the Command
needed to access them to expose them to the presentation layer.
Conclusion Link to heading
So that’s how you can get all the benefits of the Commands in newer languages without being dragged down by the semantic limitations of the Command Pattern.
An important thing to note is that this function-based approach is simpler in the very first version this was possible in Java (Java 8). Java is an OO language first and foremost. It was designed with classes as the foundation for all interactions. This language and others like it are why these kinds of patterns were necessary in the first place, and as these languages adopt certain aspects of functional languages, these OO patterns will become obsolete due to functions.
In a language that was designed from the ground up to use first-class functions, whether that be a functional language like Haskell or even another language in the JVM like Kotlin, this code is vastly simpler, especially with more advanced concepts like currying, higher order functions, etc.
Stay tuned for more parts in this series! Thanks for reading, and let me know if you have any patterns in mind that you want me to discuss!