Object Identity

Iets dat in de meeste platformen heden ten dage op het eerste gezicht goed geregeld is is het concept van object identity. In feite is dit onder water de pointer die we toewijzen (reference) aan bijvoorbeeld variabelen in onze code. Een object bevindt zich op een bepaalde plaats in het geheugen en dat is daarmee zijn unieke identificatie. Dit wordt voor je geregeld door respectievelijk een JVM of CLR of welke andere omgeving je maar mee werkt; het enige dat je moet beseffen is dat je als je echt OO bezig bent alleen referenties naar de objectstructuren heen en weer stuurt.

Lastiger wordt het als je je objecten op zeker moment uit je geheugen gaat halen om bijvoorbeeld op te slaan op disk of over een lijn te sturen in een gedistribueert systeem. Objecten zijn op verschillende manieren te ‘serialiseren’, d.w.z. platslaan om uit het geheugen te transporteren naar een andere omgeving. Dat kan een webpagina zijn maar ook een file of een database. De weg terug, de-serialiseren, maakt dat ik binnengekomen gegevens weer kan opblazen tot objecten die zich in het geheugen bevinden.
Ook dit soort scenario’s worden door resp. .NET en Java EE/SE prima ondersteunt, dat wil zeggen als ik mijn volledige objectboom vanuit mijn geheugen naar disk schrijf via zgn. binaire serialisatie. Alle referenties worden in dit proces keurig meegenomen zodat ik mijn volledige image kan wegschrijven en op later moment kan ophalen.

Lastiger wordt het als het om delen van de boom gaat; immers als ik bijvoorbeeld van een webpagina een geserialiseerd object terugkrijg hoe weet ik dan waar ik hem in de boom moet hangen? Of hetzelfde scenario van en naar databases, hetgeen overigens ook bij O/R mapping vaak voorkomt?

In mijn optiek is het in vrijwel alle gevallen van serieuze software ontwikkeling nodig om zelf zicht te kunnen houden van de identity van een object. Je wilt in verschillende contexten altijd kunnen weten om welke unieke instantie van je businessobject het gaat. Een veel gebruikt pattern ook door fowler omschreven is Identity Field. Vaak genoemd in de context van O/R mapping, maar in mijn optiek is identity veel meer iets dat centraal in je business logica geregeld moet worden. Immers, wie zegt dat je een database gebruikt in je systeem?

Ok, hoe implementeer je dat nou. Mijn voorkeur gaat uit naar een layer supertype waar je je businessobjecten van laat overerven. In principe is dit codefragment ongeveer universeel toepasbaar:

Guid id;
public Guid Id
{
     get {
          if(id==Guid.Empty)
               id = Guid.NewGuid();
          return id;
     }
     set {
          id = value;
     }
}

Andere benaderingen zijn die van geen gebruik van setter maar een constructor voor ‘bestaande’ objecten (eentje met parameter Id dus) en eentje voor nieuwe objecten die zelf een Id genereert. Afhankelijk van je O/R bridging strategie zou je een van beide kunnen kiezen. De bovenstaande werkt in elk geval goed met bijvoorbeeld NHibernate – gebruikmakend van property access. Als je field level access kiest dan zou je de setter weg kunnen laten (hetgeen in principe ook mooier is natuurlijk).

Onderwerpen die hier op volgen zijn equality en hashcodes, twee onderwerpen die sterk samenhangen met uniek identificeren van objecten in bepaalde contexten. Voor nu ben ik erg benieuwd naar ervaringen van anderen op dit gebied; hoe ga jij om met identity van je businessobjecten?