The big idea behind this pattern is that for every ‘special case’ encountered in your code you return a special, or different, object. In our employee scenario, null is a special case and hence we return a NullEmployee object instead of returning null.
A good way of implementing a NullEmployee is as an immutable singleton, that way you don’t create a multitude of unnecessary objects and it’s thread-safe.
public final class NullEmployee extends Employee {
private static final String DEFAULT_VAL = "";
private static final NullEmployee instance = new NullEmployee();
/**
* Object is an immutable singleton
*/
private NullEmployee() {
// Blank
}
@Override
public final String getFirstName() {
return DEFAULT_VAL;
}
@Override
public final String getSurname() {
return DEFAULT_VAL;
}
@Override
public final String getPhoneNumber() {
return DEFAULT_VAL;
}
/**
* @return Return the one and only immutable Null Employee
*/
public static Employee getInstance() {
return instance;
}
}
This means that any client code will not need to test for nulls:
// This will NEVER throw a NullPointerException because of the NullEmployee object
// that is returned if Bill Williams does not exist.
employee = instance.getEmployeeByName("Bill", "Williams");
System.out.println("Bill Williams phone number is:" + employee.getPhoneNumber());
// The same thing will happen if we ask for a list of employees by surname. If an empty
// list is returned then nothing bad happens.
List<Employee> employees = instance.getEmployeesBySurname("Parker");
for (Employee item : employees) {
System.out.println(item.getFirstName() + " " + item.getSurname()
+ "'s phone number is:" + item.getPhoneNumber());
}
The only other detail to think about is the Employee. It has three fields: first name, surname, and phone number and whereas first name and surname are mandatory for our purposes, we might consider phone number as optional. This means there is the additional problem of the getPhoneNumber() method possibly returning null. This leads us to revisit or original employee code to ensure that optional fields also NEVER return null:
public String getPhoneNumber() {
return phoneNumber == null ? "" : phoneNumber;
}
The benefits of using this pattern is that it achieves clean client code without no duplication of effort or code and with less likely-hood of NullPointerExceptions being raised.
2 comments:
Hi,
I have gone through your blogs and understood usage of Special Case Pattern. However I have doubt, what if I need to do something with the phone number of the Employee, and that is needed by another class. Now instead of null I will get an empty String. I am confused. Please explain More.
Thanks and Regards,
Saravanan.K
Thanks for getting in touch. The motivation for the Special Case Pattern is to make your code less brittle by avoiding NullPointerExceptions
In this example, if you don’t use the Special Case Pattern and the Employee does not have a phone, then the empty phone number attribute of the employee's record is null. Any client code that uses the phone number of the Employee class must either constantly check for a null value, or suffer a NullPointerException when the phone number is empty.
If you define an empty field as an empty string and not a null reference, then your client’s code won’t need to check for null and won’t crash. Furthermore, if the Employee class is used by 20 client’s, then by effectively moving the null check to inside the Employee, each of the 20 client’s don’t have to check for null saving a lot of time and effort.
Hope this answers your question.
Post a comment