Design Pattern Examples
Overview of object-oriented design patterns
Null Object Pattern

Diagram of the Null Object pattern

The Null Object pattern is used in those places where a default object of some kind is needed to do nothing. A Null (or Default) Object is an actual object that can be called on but does not do anything. This is not the same thing as a null reference or pointer, which represents an uninitialized variable.

A Null Object works only in those places where abstract classes or interfaces are used to represent all objects of a particular kind. One of those kinds can be a Null Object. So if you have an interface that represents commands that can be applied to a picture, it may be useful to create a command that does nothing (in assembly language parlance, a NOP or No Operation).

The concept of a "do nothing" object can be extended to functions, typically in situations where pointers to the functions (or delegates) are stored in dynamic lists to be executed in order. A function that fits in the list but otherwise does nothing when called is a Null Object (in this case, the function is treated as an object).

During initial development of such a system, it is often quite useful to have a Null Object in place. Such objects are easy to implement so no bugs are likely to be present. Then the rest of the system that actually works with the commands can be created, using the Null Object as a stand-in for real commands.

An explicit class representing a Null Object is not always needed. A class that does something could be designed to do nothing if created in a certain way or a flag is set (or cleared) on the class instance. The idea is there is an object that does nothing but acts as a stand-in for a real object that does do something.

For one example, the Bridge Pattern example has a Bridge_NullLogger class that represents a logger that does nothing. This is a classic case of a null object.

How to Use

Links to the Null Object classes or functions
C++ C# Python C
MoveProcessor class MoveProcessor class MoveProcessor class MoveProcessor_ExecuteMoveList() function
MoveProcessor_ShowMoveList()
MoveCommand base class MoveCommand base class MoveCommand base class MoveCommand structure
MoveCommand_Create()
MoveCommand_Destroy()
MoveCommandNone (Null Object) class MoveCommandNone (Null Object) class MoveCommandNone (Null Object) class MoveCommandNone_Execute() function
MoveCommandLeft class MoveCommandLeft class MoveCommandLeft class MoveCommandLeft_Execute() function
MoveCommandRight class MoveCommandRight class MoveCommandRight class MoveCommandRight_Execute() function
MoveCommandUp class MoveCommandUp class MoveCommandUp class MoveCommandUp_Execute() function
MoveCommandDown MoveCommandDown class MoveCommandDown class MoveCommandDown_Execute() function

The somewhat contrived example here parses a string for single letter move commands, converting them into class objects (C++, C#, Python) or functions (C) for each command. For all other characters in the string, a null object or function is used to represent the move command. Bad commands are not simply ignored so as to allow for showing them along with the command class assigned to execute the command.

This example also uses a form of the Command Pattern the Interpreter Pattern.

C++

void NullObject_Exercise()
{
std::cout << std::endl;
std::cout << "NullObject Exercise" << std::endl;
MoveProcessor moveProcessor;
// A stream of recognized and unrecognized move commands. The
// unrecognized commands do nothing.
std::string moveString = "ur#ld!lr";
std::cout << " Showing the move commands:" << std::endl;
moveProcessor.ShowMoveList(moveString);
std::cout << " Executing the move commands:" << std::endl;
std::cout << Helpers::formatstring(" %s -> ", moveString.c_str());
moveProcessor.ExecuteMoveList(moveString);
std::cout << " Done." << std::endl;
}
std::string formatstring(const char *fmt,...)
Use the given string and arguments to return a buffer containing the formatted string....

C#

public void Run()
{
Console.WriteLine();
Console.WriteLine("Null Object Exercise");
MoveProcessor moveProcessor = new MoveProcessor();
// A stream of recognized and unrecognized move commands. The
// unrecognized commands do nothing.
string moveString = "ur#ld!lr";
Console.WriteLine(" Showing the move commands:");
moveProcessor.ShowMoveList(moveString);
Console.WriteLine(" Executing the move commands:");
Console.Write(" {0} -> ", moveString);
moveProcessor.ExecuteMoveList(moveString);
Console.WriteLine(" Done.");
}

Python

def NullObject_Exercise():
print()
print("Null Object Exercise")
moveProcessor = MoveProcessor()
# A stream of recognized and unrecognized move commands. The
# unrecognized commands do nothing.
moveString = "ur#ld!lr";
print(" Showing the move commands:")
moveProcessor.ShowMoveList(moveString)
print(" Executing the move commands:")
print(" {0} -> ".format(moveString), end="")
moveProcessor.ExecuteMoveList(moveString)
print(" Done.")

C

void NullObject_Exercise(void)
{
printf("\nNullObject Exercise\n");
// A stream of recognized and unrecognized move commands. The
// unrecognized commands do nothing.
const char* moveString = "ur#ld!lr";
printf(" Showing the move commands:\n");
printf(" Executing the move commands:\n");
printf(" %s -> ", moveString);
printf(" Done.\n");
}
static void MoveProcessor_ExecuteMoveList(const char *moveList)
Parse and execute the given list of move commands, where each command is represents by a single chara...
static void MoveProcessor_ShowMoveList(const char *moveList)
Parse and display the given list of move commands, where each command is represents by a single chara...

RUST

(Apologies. Doxygen does not understand Rust syntax and therefore cannot colorize the code.)

pub fn nullobject_exercise() -> Result<(), String> {
println!("");
println!("NullObject Exercise");
// A stream of recognized and unrecognized move commands. The
// unrecognized commands do nothing.
let move_string = "ur#ld!lr";
let move_processor = MoveProcessor::new();
let move_commands = move_processor.parse(move_string);
println!(" Showing the move commands:");
move_processor.show_commands(&move_commands);
println!(" Executing the move commands:");
print!(" {0} -> ", move_string);
move_processor.execute_commands(&move_commands);
println!(" Done.");
Ok(())
}

See Also