Design Pattern

Null Object Pattern

Clean Java-only production-ready implementation.


Instead of returning null and forcing the caller to check if (x != null), return a "null object" that implements the same interface with no-op behavior.

// ─── EXAMPLE 1 ──────────────────────────────────────────────────────────────
// WHAT WE ARE IMPLEMENTING:
// A telemetry pipeline using safe, do-nothing fallbacks to prevent manual
// null-checks.
//
// WHERE THE NULL OBJECT FITS IN:
// Logger is the abstraction. RealLogger is the active logging component.
// NullLogger acts as the Null Object acting as a safe, silent NOP.
// ────────────────────────────────────────────────────────────────────────────
// --- Interface ---
interface Logger {
    void log(String message);
}

// --- Real ---
class ConsoleLogger implements Logger {
    public void log(String message) {
        System.out.println("  [LOG] " + message);
    }
}

// --- Null Object ---
class NullLogger implements Logger {
    public void log(String message) {
        // No-op — silently discard
    }
}

// --- Client that never checks for null ---
class ReportService {
    private final Logger logger;

    public ReportService(Logger logger) {
        this.logger = logger;
    }

    public void generateReport() {
        // Business logic...
        logger.log("Report generated");
    }
}

public class Main {
    public static void main(String[] args) {
        // With logging
        new ReportService(new ConsoleLogger()).generateReport();

        // Without logging — pass NullLogger, no null checks needed
        new ReportService(new NullLogger()).generateReport();
    }
}