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. A .Net keretrendszerben gyakran használt megoldás, hogy az osztályok tartalmaznak null objektumot osztálymezőként.

A probléma megoldható másként is. Egyes nyelvek, mint a Smalltalk a null referenciát is objektumnak tekintik, a nyelvben minden objektum elve alapján. Egyes Lisp dialektusokban, mint Common Lisp, Scheme vagy a CLOS, a nil objektum éppen az üres lista. Kacsa típusozású nyelvekben a null referencia nyújthatja azt a viselkedést, amit a null objektumtól elvárnánk.

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

Kapcsolat más mintákkal[szerkesztés]

Az állapot és a stratégia speciális esetének tekinthető.

Gammáék könyvében nem szerepel, de Martin Fowler: Refractoring[1] és Joshua Kerievsky refraktorálásról szóló könyve tartalmazza. [2]

Robert Cecil Martin: Agile Software Development: Principles, Patterns and Practices 17. fejezete foglalkozik a mintával.[3]

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.
    }
}

Kritika[szerkesztés]

A null objektum használatával vigyázni kell, mivel a hibás végrehajtás úgy tűnhet, mintha rendben lenne.

A null objektumnak egykének kell lennie, különben minden összehasonlítás lelassul, ahol ellenőrizzük, hogy valami nem null objektum-e.

Mivel a null pointer még mindig jelen van a nyelvben, a tesztelésnek ellenőriznie kell, hogy nem fordul-e mégis elő a kódban. A kódban maradt null pointerek nem okoznak fordítási hibát, ellenben futás idejű hibát igen.

A null objektum nem használható csak az olvashatóság javítására, mivel nem hagyható el a rosszabbul olvasható rész, csak áthelyezhető.

  1. Fowler, Martin. Refactoring. Improving the Design of Existing Code. Addison-Wesley (1999). ISBN 0-201-48567-2 
  2. Kerievsky, Joshua. Refactoring To Patterns. Addison-Wesley (2004). ISBN 0-321-21335-1 
  3. Martin, Robert. Agile Software Development: Principles, Patterns and Practices. Pearson Education (2002). ISBN 0-13-597444-5