Null Objects are great alternatives to The Billion Dollar Mistake. Sometimes we don't need them
TL;DR: Don't abuse patterns. Even NullObject.
Problems
Empty Classes
Namespace Polluting
Duplicated Behavior
Solutions
- Create Null Objects instantiating real-object classes.
Context
Null Object pattern is a great alternative to Nulls and IFs (Both are code smells).
The structure of the pattern tells us to create a hierarchy.
This is not really necessary, we need real objects to be polymorphic to null objects.
Inheritance is not a proper way to achieve polymorphism.
A simple solution is to create a real object behaving like a null one.
For example: '0' is numbers' null object.
'' (or "") is String's null object
An empty collection is collection's null object.
Sample Code
Wrong
abstract class Address {
public abstract String getCity();
public abstract String getState();
public abstract String getZipCode();
}
//Using inheritance for null objects is a mistake
//We should use interfaces (when available)
public class NullAddress extends Address {
public NullAddress() { }
public String getCity() {
return Constants.EMPTY_STRING;
}
public String getState() {
return Constants.EMPTY_STRING;
}
public String getZipCode() {
return Constants.EMPTY_STRING;
}
}
public class RealAddress extends Address {
private String zipCode;
private String city;
private String state;
public RealAddress(String city, String state, String zipCode) {
this.city = city;
this.state = state;
this.zipCode = zipCode;
}
public String getZipCode() {
return zipCode;
}
public String getCity() {
return city;
}
public String getState() {
return state;
}
}
Right
//There are just "addresses"
public class Address {
private String zipCode;
private String city;
private String state;
public Address(String city, String state, String zipCode) {
//Looks anemic :(
this.city = city;
this.state = state;
this.zipCode = zipCode;
}
public String zipCode() {
return zipCode;
}
public String city() {
return city;
}
public String state() {
return state;
}
}
Address nullAddress = new Address(Constants.EMPTY_STRING, Constants.EMPTY_STRING, Constants.EMPTY_STRING);
//we have our null object
//we should NOT assign it to a singleton, static or global
//It behaves like a null object. That's enough
//No premature optimizations
Detection
[X] Manual
This is a semantic smell.
Tags
- Null
Conclusion
Creating Null Object classes is sometimes overdesign.
We need to create a real object.
This real object should never be global, singleton, or static.
Too many smells to avoid.
Relations
Code Smell 18 — Static Functions
Maxi Contieri ・ Nov 6 '20
More Info
Credits
Photo by Juan Davila on Unsplash
Thanks to Hernan Wilkinson for this idea on his course Diseño a la Gorra (in Spanish)
All models are wrong but some models are useful
George Box
Software Engineering Great Quotes
Maxi Contieri ・ Dec 28 '20
This article is part of the CodeSmell Series.