Null Objektum programtervezési minta

A Wikipédiából, a szabad enciklopédiából

Az objektumorientált számítógépprogramozásban a Null Object egy objektum, amelynek a viselkedése semleges, ún. „null”. A Null Object programtervezési minta meghatározza az ilyen objektumok használatának módját és viselkedését (vagy annak hiányát). Először a Pattern Languages of Program Design könyvben jelent meg.

Létrehozásának oka[szerkesztés]

A legtöbb objektumorientált nyelvben, pl. JAVA-ban vagy C#-ban a referenciák lehetnek null tartalmúak. Ezeket a referenciákat mindig ellenőrizni kell, hogy nem null-e az értékük, mivel a metódusok tipikusan nem hívhatóak meg null referenciára.

Leírás[szerkesztés]

Ahelyett, hogy null referenciát adnánk vissza egy objektum hiányában (pl. egy nem létező vásárló), egy objektumot használunk, mely implementálja a megfelelő interfészt, de a metódus törzse üres. Ennek a megoldásnak az előnye, hogy a Null Object nagyon kiszámítható és nincsen mellékhatása: egyszerűen nem csinál semmit. Például, egy függvény visszaadhat egy listát egy mappában található fájlokról, hogy később valamilyen műveletet tudjunk végezni rajtuk. Üres mappa esetében megoldás lehet az, ha kivételt dobunk, vagy null referenciával térünk vissza. Így a kódrészletnek, ami egy listát vár ellenőriznie kell, hogy valóban listát kapott-e, ami bonyolítja a kódot. Azzal, hogy Null Object-et adunk vissza (pl. egy üres listát) már nem kell törődnünk az ellenőrzéssel, egyszerűen csak végigiterálhatunk a listán. Azt is meg lehet állapítani, ha a visszatérési érték egy Null Object (pl. egy üres lista) és szükség esetén másképpen reagálni rá. A Null Object programtervezési mintát úgy is lehet használni, hogy egy csonkként működjön, ha esetleg még nincs kész egy bizonyos funkció, pl. egy adatbázis nem elérhető a tesztelés alatt.

UML ábra

Példa[szerkesztés]

Adott egy bináris fa ezzel az elem struktúrával:

class node {
  node left
  node right
}

Implementálhatjuk a fa méret függvényt rekurzívan:

function tree_size(node) {
  return 1 + tree_size(node.left) + tree_size(node.right)
}

Mivel a gyermek csomópontok nem biztos, hogy léteznek ezért a fa méret függvényünket úgy kell módosítani, hogy a gyermek csomópontok meglétét ellenőrizze.

function tree_size(node) {
  set sum = 1
  if node.left exists {
    sum = sum + tree_size(node.left)
  }
  if node.right exists {
    sum = sum + tree_size(node.right)
  }
  return sum
}

Ez viszont a függvényt sokkal bonyolultabbá teszi. A Null Object programtervezési minta használatával készíthetünk egy speciális fa méret függvényt, ami csak a null csomópontokkal foglalkozik.

function tree_size(node) {
  return 1 + tree_size(node.left) + tree_size(node.right)
}
function tree_size(null_node) {
  return 0
}

Ez elválasztja a sima logikát a speciális esetkezeléstől és egyszerűbbé teszi a kód megértését.

C# példakód[szerkesztés]

C# nyelven a Null Object minta megfelelően implementálható. Ez a példa Állat objektumokat készít és a NullAnimal objektumot használja a C# null kulcsszava helyett. A Null Object egységes működést eredményez és megelőzi a futásidejű Null Reference Exception létrejöttét, ami akkor jönne létre, ha a C# null kulcsszavát használnák.

/* Null Object minta implementáció:
 */
using System;
 
// Az Animal interfész a kulcs a különböző Animal implementációk kompatibilitásához.
interface IAnimal
{
    void MakeSound();
}
 
// A kutya egy igazi állat.
class Dog : IAnimal
{
    public void MakeSound()
    {
        Console.WriteLine("Woof!");
    }
}
 
// A Null eset: ez a NullAnimal osztály példányosítható és használható a C# null kulcsszava helyett.
class NullAnimal : IAnimal
{
    public void MakeSound()
    {
        // Céltudatosan nem csinál semmit.
    }
}
 
/* =========================
 * Egyszerű használatra példa
 */
static class Program
{
    static void Main()
    {
        IAnimal dog = new Dog();
        dog.MakeSound(); // Kimenet: "Woof!"
 
        /* A C# null helyett NullAnimal példányt használunk.
         * Ez a példa egyszerű, de közvetíti az ötletet miszerint, ha a NullAnimal példányt használjuk, akkor a program
         * sosem fut .NET System.NullReferenceException kivételre futásidőben, mintha a C# null kulcsszavát használtuk volna.
         */
        IAnimal unknown = new NullAnimal(); //<< helyettesítés: IAnimal unknown = null;
        unknown.MakeSound(); // a kimenet semmi, de legalább nem dob futásidejű kivételt.
    }
}