LESSON 8.2
Null object
Provide an object as a surrogate for the lack of an object of a given type. Null Object provides intelligent do-nothing behavior, eliminating null checks.
6 min read
Defensive programming often clutters domain code with endless null checks: if (user != null && user.subscription != null && user.subscription.plan != null). A single missing check in production leads to fatal Cannot read properties of null or NullPointerException crashes.
The problem
// Defensive null checks littering every method:
class OrderService {
#logger;
constructor(logger = null) {
this.#logger = logger;
}
processOrder(order) {
// Boilerplate everywhere:
if (this.#logger) {
this.#logger.log(`Processing order: ${order.id}`);
}
// business logic...
if (this.#logger) {
this.#logger.log(`Order complete`);
}
}
}The pattern
Null Object implements the target interface with safe, neutral "do-nothing" behavior. Instead of returning null or leaving references uninitialized, the system supplies a default NullObject (e.g. NullLogger, NullDiscount, GuestUser). Callers invoke methods polymorphically without checking for null.
The intent: Provide an object as a surrogate for the lack of an object of a given type. The Null Object provides intelligent do-nothing behavior, eliminating defensive null checks.
In code
When to use it, and when not to
Use Null Object when:
- An object requires a collaborator, but sometimes that collaborator does nothing (e.g. logging, telemetry, metrics, discounts).
- You want clients to treat real collaborators and absent collaborators uniformly without defensive
if (x == null)branching.
Don't use Null Object when:
nullrepresents a critical error or an uninitialized state that should fail loudly and immediately.- The absence of data requires branching logic in the user interface (e.g. showing a Login prompt when User is null).
Where you have already seen it
In Java 8+, Optional.empty() is a functional variant of the Null Object pattern. In Linux and Unix filesystems, /dev/null is an operating system-level Null Object that safely absorbs all written bytes. In game loops, a NullAudioDevice is used when running games in headless automated CI pipelines.
Related patterns
- Null Object vs State: A Null Object can be viewed as a special state in the State pattern that performs no actions.
- Null Object vs Strategy: Null Object often serves as the default, no-op strategy in a Strategy pattern setup.
Try it
Logging Framework LLD
Add a NullLogger to an extensible logging framework that discards records with zero CPU overhead.