Null Object Pattern


Null Object Pattern

Motivation

The Null Object pattern can be used to avoid having checks that objects are not null before using them to avoid throwing NullReferenceExceptions, e.g.

if (myObject == null)
{
   return;
}
// do something with myObject…

Example

For example, say we have a device object with a Connect() method that a client wishes to call. If we're getting the device from a repository we have to do a check for null before calling Connect(). If however the repository returns the null object, no null check is required. The null check is done within the repository so the client code does have to worry about it.


Null object code

public interface IDevice
    {
        string Name { get; set; }

        void Connect ();
    }

    public class RealDevice : IDevice
    {
        public string Name { get; set; }

        public void Connect ()
        {
            Console.WriteLine("Device is connecting...");
        }
    }

    public class NullDevice : IDevice
    {
        public string Name
        {
            // Return something making it obvious this is the null object.
            get { return "null device"; }

            set { /* do nothing */ }
        }

        public void Connect ()
        {
            // Normally the method in the null object will just do nothing.
            Console.WriteLine("Device is null so do nothing");
        }

    }

Repository code

public interface IDeviceRepository
    {
        IDevice GetDeviceByName (string name);
    }

    public class DeviceRepository : IDeviceRepository
    {
        private List<IDevice> _devicesList;

        public DeviceRepository ()
        {
            _devicesList = new List<IDevice>
            {
                new RealDevice() { Name = "Camera" },
                new RealDevice() { Name = "Gripper" }
            };
        }

        public IDevice GetDeviceByName (string name)
        {
            IDevice device = _devicesList.SingleOrDefault(dev => dev.Name == name);

            // Do the null check here instead of in the client code.
            if (device == null)
            {
                device = new NullDevice();
            }

            return device;
        }
    }

Client code

class Program
    {
        private static IDeviceRepository _deviceRepository = new DeviceRepository();

        static void Main (string[] args)
        {
            // Valid will talk to real object.
            ConnectToDevice("Camera");

            // Invalid so will talk to null object.
            ConnectToDevice("any old name");

            Console.Read();
        }

        public static void ConnectToDevice(string deviceName)
        {
            IDevice device = _deviceRepository.GetDeviceByName(deviceName);
            device.Connect();
        }
    }


UML class diagram





Code

The example code is on Github.

Comments

Popular posts from this blog

Path environmental variable on mac

Setting up node-sass on a mac