В об'єктно-орієнтованому програмуванні, Null Object або нульовий об'єкт — це об'єкт з визначеною нейтральною (англ.null) поведінкою. Шаблон проєктування Null Object описує використання цих об'єктів та їх поведінки або відсутності таких. Вперше цей шаблон було описано в серії книжок Pattern Languages of Program Design.[1]
Традиційно, методи, що повертають об'єкти (наприклад, методи твірних шаблонів) у випадку невдачі (наприклад, пошук об'єкту в порожній колекції) повинні повертати коректне значення посилання — null.
Обробка цього результату може бути реалізована простою перевіркою посилання на null перед викликом методів.
// Приклад на JavaclassAnimal{publicvoidmakeSound(){System.out.write("Гав-гав!");}}...Animalpet=animalsProvider.getAnimal();if(pet!=null){pet.makeSound();}else{/* обробка помилки */}...
Проблему обробки null-посилань і вирішує шаблон Null object.
Треба відзначити, що, наприклад, у мові програмування Objective-C використовується інший підхід до цієї проблеми: всі методи, що викликаються через nil-посилання (nil близька за сенсом до null частина Objective-C) повертають також nil.
Опис
Замість використання null-посилання для відображення відсутності об'єкту треба використовувати спеціальний об'єкт, який реалізує потрібні інтерфейси, але не має поведінки, тобто має пусті методи. Перевагою цього підходу є те, що реалізація нульового об'єкту завжди передбачувана: вона нічого не робить, а тому не має таких побічних ефектів, які має null-посилання.
Наприклад, функція повинна прочитати список файлів в директорії та виконати якісь дії з кожним. В випадку, якщо директорія порожня, можна повернути null або згенерувати виняток. Таким чином, код, що очікує список файлів повинен перевіряти, чи дійсно він отримав список, а це в свою чергу ускладнює структуру програми.
Якщо повертати нульовий об'єкт (наприклад, порожній список), то зникає необхідність перевірок. Викликаючий код може ітерувати список файлів, не зважаючи на можливі помилки і не виконувати ніяких дій при цьому.
Хоча, залишається можливим робити дещо змінену перевірку: «чи дорівнює результат нульовому об'єкту?», та діяти далі за логікою програми.
Також, цей шаблон може використовуватися як заглушка при тестуванні.
Відношення до інших шаблонів
Шаблон може розглядатися як спеціальний випадок шаблонів Стан (англ.State) та Стратегія (англ.Strategy). Він не написаний в книзі GoF, а був запропонований Мартіном Фаулером[2] та Джошуа Керієвскі[3].
В мовах
C++
Мова зі статично типізованими посиланнями на об'єкти показує, як нульовий об'єкт стає складнішим шаблоном.
Існують ситуації, коли вказівник або посилання на об'єкт класу animal необхідний, але за ним немає належного об'єкту. Посилання не може бути null, коли вказівник animal * — може: такий вказівник можна використовувати для зберігання об'єкту, але неможливо безпосередньо викликати методи. Код a->make_sound() викличе помилку undefined behavior (укр.невизначена поведінка), якщо a буде null-вказівником.
Шаблон Null object вирішує цю проблему, впроваджуючи спеціальний клас null_animal, який може бути інстанційований та викорстовуватись з вказівником чи посиланням на animal.
C#
С# є мовою, в якій шаблон Null object можна реалізувати канонічно. В нижче наведеному прикладі, нульовий об'єкт реалізує очікувану порожню поведінку та попереджає проблеми часу виконання програми, а сам виняток Null Reference Exception, який буде згенеровано, якщо відбудеться використання null-посилання.
usingSystem;interfaceAnimal{voidMakeSound();}classDog:Animal{publicvoidMakeSound(){Console.WriteLine("Woof!");}}classNullAnimal:Animal{publicvoidMakeSound(){}}staticclassProgram{staticvoidMain(){Animaldog=newDog();dog.MakeSound();//Animalunknown=newNullAnimal();//<< замінює: Animal unknown = null;unknown.MakeSound();// нічого не відбувається}}
Smalltalk
За принципом Smalltalk, «все є об'єктом», відсутність якогось об'єкту моделюється об'єктом nil. В GNUSmalltalk, наприклад, nil є об'єктом класу UndefinedObject, прямого нащадка Object.
Будь-яка операція, яка не змогла повернути потрібний об'єкт може повернути nil замість нього, таким чином, попереджаючи повернення «об'єкту нема». Цей підхід спрощує програму, позбавляючи від null-посилань, null-вказівників.
Ruby
В Ruby нульовий об’єкт це повноцінний об’єкт класу NilClass. Він специфічним чином працює в логічних виразах: він приймає значення false. Ruby дозволяє розширювати цей клас, тому, якщо ви хочете таку ж поведінку, як у в Objective-C, тоді використовуйте щось на кшталт цього: