Provide a surrogate for another object that shares the same interface but does nothing.
The Null Object encapsulates the implementation decisions of how to do nothing and hides those details from its collaborators.
Sometimes, a client requests a behavior from a collaborator class
The collaborator class is optional: if it is not present, the expected behavior is to do nothing
The client wants to use the the collaborator transparently, without checking for nulls every time.
Consider a logging facility with two implementations: file and console logging
Services can use either implementations.
However, a service is not necessarily required to use a log (the association between Service
and Log
is optional)
Therefore, the Service must check for null values before using the log
an object requires a collaborator and
some collaborator instances may be null and
collaborator instances must be checked before every use and
the result of a null check is to do nothing or execute a default behavior
Create a class that implements the same interface as the collaborator class and
Implement all its methods to do nothing or provide default results and
Use an instance of this class whenever the collaborator reference would have been null
requires a collaborator
declares a common interface for collaborators
provides the actual behavior that the Client expects
does nothing.
Doing nothing depends on the behavior the Client is expecting. When there is more than one way of doing nothing, more than one Null Collaborator may be required.
Clients ignore if they are working with null objects
The client code is simpler
The null/default behavior is encapsulated in a single class
This behavior can be shared with other classes
Null values are typed
May need to create a Null Collaborator for every new abstract class
Hard to implement if clients do not agree on what the null behavior should do
Always acts as a Null Collaborator, cannot be transformed into an Actual Collaborator
public abstract class AbstractCustomer {
protected String name;
public abstract boolean isNil();
public abstract String getName();
}
public class RealCustomer extends AbstractCustomer {
public RealCustomer(String name) {
this.name = name;
}
@Override
public String getName() {
return name;
}
@Override
public boolean isNil() {
return false;
}
}
public class NullCustomer extends AbstractCustomer {
@Override
public String getName() {
return "Not Available in Customer Database";
}
@Override
public boolean isNil() {
return true;
}
}
public class CustomerFactory {
public static final String[] names = {"Rob", "Joe", "Julie"};
public static AbstractCustomer getCustomer(String name){
for (int i = 0; i < names.length; i++) {
if (names[i].equalsIgnoreCase(name)){
return new RealCustomer(name);
}
}
return new NullCustomer();
}
}
Optional.empty() : Optional<T> (1)
Optional.of(T t) : Optional<T> (2)
Optional.ofNullable(T t) : Optional<T> (3)
1 | Returns an Optional with no value |
2 | Returns an Optional with the value t |
3 | Returns an Optional that may contain a value (calls empty() or of(T) depending whether t is null ) |
class Main {
Optional<Customer> customer = Optional.empty();
public void setCustomer(Customer c) {
customer = Optional.ofNullable(c);
}
public void print() {
customer.ifPresent(each => System.out.println(each))
}
}
"Null Object — Something for Nothing". Kevlin Henney, March 2003.
"The Null Object Pattern". Bobby Woolf, July 1996.
"Smart Nil". Panu Viljamaa, 1997
"Null Object Pattern". Jeffery Walker, 2002.
public class Collections {
public static final List EMPTY_LIST = new EmptyList<>();
public static final <T> List<T> emptyList() {
return (List<T>) EMPTY_LIST;
}
private static class EmptyList<E>
extends AbstractList<E>
implements RandomAccess, Serializable {
// (...)
public int size() {return 0;}
public boolean isEmpty() {return true;}
public void clear() {}
public boolean contains(Object obj) {return false;}
public boolean containsAll(Collection<?> c) { return c.isEmpty(); }
}
}