23 02 2014
Null Object Pattern
As announced in my previous post about Introducing Design Patterns, I will start with the first concrete post about the “Null Object Pattern”. For this I will take the chess board example from Indexed Properties.
What is the Null Object Pattern? It is a design pattern that belongs to the “Behavioral patterns”. This object does nothing. It is representative for nothing. The following UML diagramm will explain the simple structure.
So, why we don’t simply use null instead of this “Null object”? One reason is to prevent “Null reference exceptions”. Another advantage is to use null objects together with “The Visitor Pattern” (I will explain it, in a following post). Let’s get practical. In our chess board example we have used indexed properties to get the specified field on the board. Now it’s time to fill the field with live. But first let’s take a look at the current Field class.
1 2 3 4 5 6 7 |
public sealed class Field { public override string ToString() { return "Hello! I'm a field!"; } } |
I think the ToString method is very lonely – So lets add some stuff. Lets add a new property called “Value” that contains a value from a new class “Figure”. This class is abstract, because we derive the concrete chess figures from it. Furthermore we want to add the initialization into the Board class. Let’s do that in one step (Sorry for the long code, but I think it’s better that we have one base for the following steps). We will ignore the behaviour of each figure in our example, like start and end position, and movement validation, because we will focus on the structure – and I want to tell you something about the “Null Object Pattern” 😉
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 |
public static partial class Program { public enum Color { None = 0, White = 1, Black = 2 } public static void Main(string[] args) { Board chessBoard = new Board(); } public sealed class Board { private readonly Field[,] matrix = new Field[8, 8]; public Board() { // Create the fields for (int x = 0; x < 8; x++) { for (int y = 0; y < 8; y++) { this.matrix[x, y] = new Field(x, y, ); } } this.Reset(); } public Field this[int x, int y] { get { return this.matrix[x, y]; } } public Field this[int index] { get { int x = index % 8; int y = index / 8; return this[x, y]; } } public Field this[char letter, int number] { get { return this[letter - 'A', number - 1]; } } public Field this[string position] { get { return this[position[0], position[1] - 48]; } } public void Reset() { // Create the figures for (int x = 0; x < 8; x++) { for (int y = 0; y < 8; y++) { this.matrix[x, y].Figure = null; } } // Create the Rooks this["A1"].Figure = new Rook(Color.White); this["H1"].Figure = new Rook(Color.White); this["A8"].Figure = new Rook(Color.Black); this["H8"].Figure = new Rook(Color.Black); // Create the Knights this["B1"].Figure = new Knight(Color.White); this["G1"].Figure = new Knight(Color.White); this["B8"].Figure = new Knight(Color.Black); this["G8"].Figure = new Knight(Color.Black); // Create the Bishops this["C1"].Figure = new Bishop(Color.White); this["F1"].Figure = new Bishop(Color.White); this["C8"].Figure = new Bishop(Color.Black); this["F8"].Figure = new Bishop(Color.Black); // Create the Queens this["D1"].Figure = new Queen(Color.White); this["D8"].Figure = new Queen(Color.Black); // Create the Kings this["E1"].Figure = new King(Color.White); this["E8"].Figure = new King(Color.Black); // Create the Pawns this["A2"].Figure = new Pawn(Color.White); this["B2"].Figure = new Pawn(Color.White); this["C2"].Figure = new Pawn(Color.White); this["D2"].Figure = new Pawn(Color.White); this["E2"].Figure = new Pawn(Color.White); this["F2"].Figure = new Pawn(Color.White); this["G2"].Figure = new Pawn(Color.White); this["H2"].Figure = new Pawn(Color.White); this["A7"].Figure = new Pawn(Color.Black); this["B7"].Figure = new Pawn(Color.Black); this["C7"].Figure = new Pawn(Color.Black); this["D7"].Figure = new Pawn(Color.Black); this["E7"].Figure = new Pawn(Color.Black); this["F7"].Figure = new Pawn(Color.Black); this["G7"].Figure = new Pawn(Color.Black); this["H7"].Figure = new Pawn(Color.Black); } } public sealed class Field { private readonly int x; private readonly int y; public Field(int x, int y, Figure figure = null) { this.Figure = figure; this.x = x; this.y = y; } public Figure Figure { get; set; } public int X { get { return this.x; } } public int Y { get { return this.y; } } public char Letter { get { return (char)(this.x + 'A'); } } public int Number { get { return this.y + 1; } } public string Position { get { return string.Concat(this.Letter, this.Number.ToString(CultureInfo.InvariantCulture)); } } public override string ToString() { return "Hello! I'm a field!"; } } public abstract class Figure { private readonly Color color; private readonly Action action; protected Figure(Color color, Action action) { this.color = color; this.action = action; } public Color Color { get { return this.color; } } public string Name { get { return this.ToString(); } } public override string ToString() { return this.GetType().Name; } public void ExecuteAction() { this.action.Invoke(); } } public sealed class King : Figure { public King(Color color) : base(color, () => Console.WriteLine("I'm a King!")) { } } public sealed class Queen : Figure { public Queen(Color color) : base(color, () => Console.WriteLine("I'm a Queen!")) { } } public sealed class Knight : Figure { public Knight(Color color) : base(color, () => Console.WriteLine("I'm a Knight!")) { } } public sealed class Bishop : Figure { public Bishop(Color color) : base(color, () => Console.WriteLine("I'm a Bishop!")) { } } public sealed class Rook : Figure { public Rook(Color color) : base(color, () => Console.WriteLine("I'm a Rook!")) { } } public sealed class Pawn : Figure { public Pawn(Color color) : base(color, () => Console.WriteLine("I'm a Pawn!")) { } } } |
Now our chess board is filled with figure at initial positions and we can easily call “ExecuteAction” for the figure at “C2”. You will see, that we get “I’m a Pawn” as output.
1 2 3 4 5 6 |
public static void Main(string[] args) { Board chessBoard = new Board(); Field chessField = chessBoard["C2"]; chessField.Figure.ExecuteAction(); } |
But what is when we call “ExecuteAction” for “C3”? Because there is no figure on it, we will get a NullReferenceException. To prevent this, we have to check for null.
1 2 3 4 5 6 7 8 9 10 11 12 |
public static void Main(string[] args) { Board chessBoard = new Board(); Field chessField = chessBoard["C3"]; // chessField.Figure.ExecuteAction(); will throw a NullReferenceException // Therefore we have to check for chessField.Figure != null if (chessField.Figure != null) { chessField.Figure.ExecuteAction(); } } |
I think you will agree, that this is not an elegant way. This is the point where the “Null Object Pattern” makes sense.
Now we have to do two things: Create An “Empty” class derived from “Figure”. And assign that to all fields with no value. In our example we will do that in the Reset method where we create/assign the figures.
1 2 3 4 5 6 7 |
public sealed class Empty : Figure { public Empty() : base(Color.None, () => { }) { } } |
1 2 3 4 5 6 7 8 |
// Create the figures for (int x = 0; x < 8; x++) { for (int y = 0; y < 8; y++) { this.matrix[x, y].Figure = new Empty(); } } |
We are now able to call “ExecuteAction” on a field that has no figure – and it will simply do nothing.
1 2 3 4 5 6 7 8 |
public static void Main(string[] args) { Board chessBoard = new Board(); Field chessField = chessBoard["C3"]; // This will simply do nothing chessField.Figure.ExecuteAction(); } |
Maybe you think: “To much effort – Checking for null will also meet the needs.” Yes maybe you’re right, but if you have more complex code and use those objects in many places, you have to check for null every single time – and it can easily happen, that you miss one check 😉
In the next post about “Design Patterns” I will talk about the “Visitor Pattern”, that is a good following to this.
Hope you enjoyed this post. Have a nice day!
Introducing Design Patterns Oracle: Multiple call of nextval for sequences