# 2926. Design Pattern - Null ObjectNull Object

Behavioral Pattern: Null Object Pattern.

## 1. Null Object Pattern

The Null Object pattern is used to encapsulate the absence of an object by providing a substitutable alternative that offers suitable default do nothing behavior. In short, a design where “nothing will come of nothing”.

Use the Null Object pattern when:

• an object requires a collaborator. The Null Object pattern does not introduce this collaboration–it makes use of a collaboration that already exists
• some collaborator instances should do nothing
• you want to abstract the handling of null away from the client

## 2.1 Interface

public interface Shape {
double area();
double perimeter();
void draw();
}


## 2.2 Classes

public class Circle implements Shape {

}

@Override
public double area() {
// Area = πr^2
}

@Override
public double perimeter() {
// Perimeter = 2πr
return 2 * Math.PI * radius;
}
@Override
public void draw() {
System.out.println("Drawing Circle with area: " + area() + " and perimeter: " + perimeter());
}
}

public class Rectangle implements Shape {
private final double width;
private final double height;

public Rectangle (double width, double height) {
this.width = width;
this.height = height;
}

@Override
public double area() {
// A = w * h
return width * height;
}

@Override
public double perimeter() {
// P = 2(w + h)
return 2 * (width + height);
}

@Override
public void draw() {
System.out.println("Drawing Rectangle with area: " + area() + " and perimeter: " + perimeter());
}
}

public class Triangle implements Shape {
private final double a;
private final double b;
private final double c;

public Triangle (double a, double b, double c) {
this.a = a;
this.b = b;
this.c = c;
}

@Override
public double area() {
// Using Heron's formula:
// Area = SquareRoot(s * (s - a) * (s - b) * (s - c))
// where s = (a + b + c) / 2, or 1/2 of the perimeter of the triangle
double s = (a + b + c) / 2;
return Math.sqrt(s * (s - a) * (s - b) * (s - c));
}

@Override
public double perimeter() {
// P = a + b + c
return a + b + c;
}

@Override public void draw() {
System.out.println("Drawing Triangle with area: " + area() + " and perimeter: " + perimeter());
}
}


### 2.3 Problematic Usage

public class ShapeFactory {
public static Shape createShape(String shapeType) {
Shape shape = null;
if ("Circle".equalsIgnoreCase(shapeType)) {
shape = new Circle(3);
} else if ("Rectangle".equalsIgnoreCase(shapeType)) {
shape = new Rectangle(2, 4);
} else if ("Triangle".equalsIgnoreCase(shapeType)) {
shape = new Triangle(3, 4, 5);
} // else return null

return shape;
}
}


When client using this factory to get shape instance, null-check is required if it returns null object. Otherwise, NullPointerException occurs.

public class ShapeProcessor {
String[] shapeTypes = new String[] { "Circle", "Triangle", "Rectangle", null};

public ShapeProcessor () {

}

public void process() {
for (String shapeType : shapeTypes) {
Shape shape = ShapeFactory.createShape(shapeType);
if (shape != null) { // null-check is required if factory returns null object
System.out.println("Shape area: " + shape.area());
System.out.println("Shape Perimeter: " + shape.perimeter());
shape.draw();
System.out.println();
}
}
}
}


### 2.4 Implementation with NullObject Pattern

Create ‘null’ class as default shape.

public class NullShape implements Shape {

public NullShape () {}

@Override
public double area() {
return 0.0d;
}

@Override
public double perimeter() {
return 0.0d;
}

@Override
public void draw() {
System.out.println("Null object can't be drawn");
}
}


Factory can now return the null object.

public class ShapeFactory {
public static Shape createShape(String shapeType) {
Shape shape = null;
if ("Circle".equalsIgnoreCase(shapeType)) {
shape = new Circle(3);
} else if ("Rectangle".equalsIgnoreCase(shapeType)) {
shape = new Rectangle(2, 4);
} else if ("Triangle".equalsIgnoreCase(shapeType)) {
shape = new Triangle(3, 4, 5);
} else {
shape = new NullShape();
}
return shape;
}
}


Now, client doesn’t need the null check.

public class ShapeProcessor {
String[] shapeTypes = new String[] { "Circle", "Triangle", "Rectangle", null};

public ShapeProcessor () {

}

public void process() {
for (String shapeType : shapeTypes) {
Shape shape = ShapeFactory.createShape(shapeType);
// no null-check required since shape factory always creates shape objects
System.out.println("Shape area: " + shape.area());
System.out.println("Shape Perimeter: " + shape.perimeter());
shape.draw();
System.out.println();
}
}
}


Output.

Shape area: 28.274333882308138
Shape Perimeter: 18.84955592153876
Drawing Circle with area: 28.274333882308138 and perimeter: 18.84955592153876

Shape area: 6.0
Shape Perimeter: 12.0
Drawing Triangle with area: 6.0 and perimeter: 12.0

Shape area: 8.0
Shape Perimeter: 12.0
Drawing Rectangle with area: 8.0 and perimeter: 12.0

Shape area: 0.0
Shape Perimeter: 0.0
Null object cant be drawn