9. Concetti sui database Object-Oriented Michele Nasti 09. Concetti sui database Object-Oriented Il primo linguaggio di programmazione object-oriented (O-O) è SIMULA (fine anni ’60). SIMULA definisce il concetto di classe, che raggruppa la struttura di dati interna di un oggetto in una dichiarazione di classe e un tipo di dato astratto, che nasconde la struttura interna e specifica tutte le possibili operazioni esterne, portando al concetto di incapsulamento. SMALLTALK, sviluppato al Xerox Parc, (anni '70) è uno dei primi linguaggi a incorporare concetti di message passing ed ereditarietà. SMALLTALK è un linguaggio Object-Oriented puro, a differenza di linguaggi ibridi come C++, che incorpora concetti O-O nel linguaggio C. Il linguaggio O-O puro più diffuso al momento è JAVA. Un oggetto tipicamente ha due componenti: uno stato (o valore) e un comportamento (o operazioni). Un oggetto è simile ad una variabile, ma con due differenze: può rappresentare una struttura dati complessa, e può avere una serie di operazioni specifiche, definite dal programmatore. In un linguaggio di programmazione O-O, gli oggetti esistono solo durante l'esecuzione del programma (sono detti transienti) . Un database ad oggetti può estendere l'esistenza di un oggetto memorizzandolo su una memoria secondaria: gli oggetti sono quindi persistenti, esistendo anche dopo la terminazione del programma che li ha definiti. Gli oggetti persistenti possono essere condivisi da più programmi. Un obiettivo dei database O-O è di mantenere una corrispondenza diretta tra gli oggetti del mondo reale e del database, in modo che gli oggetti non perdano la loro integrità ed identità. A tal fine, essi forniscono per ciascun oggetto un identificatore univoco di oggetto, detto OID, generato dal sistema. L'OID può essere visto come equivalente al concetto di chiave primaria nei database relazionali. Una caratteristica dei database O-O è che gli oggetti possono essere caratterizzati da una struttura complessa arbitraria, per contenere tutte le informazioni necessarie. In contrasto, nei database system tradizionali, l'informazione su un oggetto complesso è spesso frammentata su molte relazioni o record, portando ad una perdita di corrispondenza tra un oggetto del mondo reale e la sua rappresentazione nel database. La struttura interna di un oggetto comprende la specifica di variabili di istanza e di operazioni . Le variabili di istanza mantengono i valori che definiscono lo stato interno dell'oggetto. Esse sono simili al concetto di attributo, ma sono incapsulate nell'oggetto e non sono necessariamente visibili all'esterno. Possono essere di un tipo di dato arbitrario. Le operazioni specificano le funzioni che possono essere applicate a quell'oggetto. Per incoraggiare l'incapsulamento, molti sistemi O-O prevedono la definizione delle operazioni applicabili a un oggetto. In tal caso un'operazione è definita in due parti: la signature (o interfaccia), che specifica il nome dell'operazione e gli argomenti e il metodo (o corpo), contenente l'implementazione dell'operazione. L'incapsulamento consente la modifica della struttura interna di un oggetto e/o dell'implementazione delle sue operazioni, senza che i programmi che le utilizzano debbano essere modificati. Affinché un sistema possa definirsi object- oriented, deve supportare due caratteristiche fondamentali: Una gerarchia di classi (o ereditarietà) e il polimorfismo degli operatori. www.ilparticolarenascosto.it Basi di dati 2 @ Unisa 9.1 9. Concetti sui database Object-Oriented Michele Nasti Il concetto di gerarchia di tipo o di classe (o ereditarietà) consente la specifica di nuovi tipi o classi ereditando la struttura e le operazioni di tipi o classi già definite. In questo modo si facilita lo sviluppo incrementale dei tipi ed il riuso del codice. In presenza di polimorfismo degli operatori un nome di operazione può riferire a varie implementazioni distinte, in base al tipo di oggetti cui è applicato. Esempio: l'operatore “+” è polimorfo, poiché può essere applicato ad operandi di tipi diversi: se gli operandi sono interi, viene invocata l'addizione su interi. se gli operandi sono reali, viene invocata l'addizione su reali. Un problema nei DBMS O-O riguarda la rappresentazione di relazioni tra oggetti. Nei primi DBMS O-O si riteneva che le relazioni non dovessero essere esplicitamente rappresentate, ma piuttosto descritte da appropriati metodi che localizzano gli oggetti relati. Questo approccio si è rilevato sbagliato quando applicato a database complessi con relazioni multiple, poiché non si ha la visibilità delle relazioni. Lo standard ODMG 2.0 ha riconosciuto questo problema, ed ora molti modelli di dati O-O permettono la rappresentazione di relazioni attraverso referenze inverse, cioè memorizzando nell'oggetto l'OID di oggetti relati. Costruttori di tipo, struttura ed identificatore di oggetti Un DBMS O-O fornisce un identificatore univoco a ciascun oggetto memorizzato del database, l'object identifier: L'OID è immutabile, ed è auspicabile che ciascun OID sia usato una sola volta (se un oggetto viene rimosso dal DB, il suo OID non deve essere riassegnato). Alcuni DBMS O-O, utilizzano come OID l'indirizzo in memoria dell'oggetto . Ciò può creare problemi in caso di riorganizzazione della memoria. Più correttamente, altri sistemi utilizzano un intero lungo, che, grazie ad una funzione hash, viene mappato sull'indirizzo di memoria dell'oggetto. Alcuni modelli O-O richiedono che qualsiasi cosa sia rappresentata come oggetto, sia esso un valore semplice o un oggetto complesso. Esempio: 50 → peso in chilogrammi, 50 → età di un uomo dovrebbero essere il valore di due oggetti diversi. Per evitare la proliferazione di oggetti, molti OODBMS consentono sia la rappresentazione di oggetti che di valori. Lo stato di un oggetto complesso può essere costruito da altri oggetti (o valori) mediante un costruttore di tipo. Formalmente un oggetto è una tripla (i, c, v), dove: – i è l'OID, – c è un costruttore di tipo, – v è il valore (o stato). Costruttori di base: atom, set, tuple, list, bag ed array. Il valore di un oggetto v è interpretato sulla base del valore di c nella tripla (i, c, v): – se c = atom → v è un valore atomico dal dominio D.; www.ilparticolarenascosto.it Basi di dati 2 @ Unisa 9.2 9. Concetti sui database Object-Oriented Michele Nasti – Se c = set → v è un insieme di OID {i1, i2, ..., in}. – Se c = tuple → v è una tupla della forma <a1:i1, a2:i2 ,..., an:in>, dove aj è un nome di attributo (istanza di variabile) e ij è un OID. – Se c = list → v è una lista ordinata di OID [i1, i2, ..., in] dello stesso tipo. – Se c = array → v è un array di OID. Un bag è identico ad un set, ma non è necessario che tutti gli oggetti siano distinti. Set, list, array e bag sono detti collection types (o bulk types), per distinguerli dai tipi di base. Esempio. Un possibile stato di base di dati relazionale dello schema COMPANY. www.ilparticolarenascosto.it Basi di dati 2 @ Unisa 9.3 9. Concetti sui database Object-Oriented Michele Nasti Una serie di oggetti atomici del database “Company”: – o1 = (i1, atom, Houston) – o2 = (i2, atom, Bellaire) – o3 = (i3, atom, Sugarland) – o4 = (i4, atom, 5) – o5 = (i5, atom, Research) – o6 = (i6, atom, 22-May-78) Una serie di oggetti complessi del database “Company”: – o7 = (i7, set, {i1,i2,i3}) – o8 = (i8, tuple, <DNAME: i5, DNUMBER: i4, MGR: i9, LOCATIONS: i7, EMPLOYEES: i10, PROJECTS:i11>) – o9 = (i9, tuple, <MANAGER: i12, MGR_STARTDATE: i6>) – o10 = (i10, set, {i12,i13,i14}) – o11 = (i11, set, {i15,i16,i17}) Un oggetto può essere rappresentato con un grafo, realizzato mediante applicazioni ricorsive dei costruttori di tipo. Come si costruisce il grafo di un oggetto oi: 1. Si crea un nodo labellato con l'OID ed il costruttore c. 2. Viene creato un nodo per ciascun valore di base del dominio D: Se ha un valore atomico, si crea un arco orientato dal nodo oi al nodo che rappresenta il valore; se il valore è costruito, si crea un arco dal nodo oi al nodo che rappresenta il valore costruito. Rappresentazione dell'oggetto complesso “Department” (O8 nell‟esempio precedente) per mezzo di un grafo. www.ilparticolarenascosto.it Basi di dati 2 @ Unisa 9.4 9. Concetti sui database Object-Oriented Michele Nasti Usando i grafi, è possibile definire oggetti uguali ed identici: due oggetti hanno valori identici se i grafi sono identici, inclusi gli OID, ad ogni livello. Due oggetti hanno valori uguali se la struttura del grafo è la stessa, ma ai nodi interni possono corrispondere diversi OID. Esempio. Consideriamo i seguenti oggetti: – o1 = (i1, tuple, <a1:i4, a2:i6>) – o2 = (i2, tuple, <a1:i5, a2:i6>) – o3 = (i3, tuple, <a1:i4, a2:i6>) Gli oggetti o1 e o2 sono uguali ma non identici. Gli oggetti o1 e o3 sono identici. I costruttori di tipo sono utilizzati per definire le strutture dati in uno schema di database O-O. Sono specificati utilizzando un O-O DDL . Le keyword tuple, set e list definiscono costruttori di tipo. I tipi di dati standard (boolean, integer, ecc...) definiscono i tipi atomici. Gli attributi che riferiscono ad altri oggetti sono referenze. Si rappresentano così relazioni tra tipi di oggetti. Esempio. ← riferimento ad un altro oggetto Illustrazione 1: La specifica deitipi di oggetto“Employee”,“Date” e“Department” inO-O DDL. Incapsulamento di Operazioni, Metodi e Persistenza I concetti di information hiding e di incapsulamento possono essere applicati agli oggetti dei database. La struttura interna dell'oggetto è nascosta, e l'oggetto è accessibile solo attraverso un certo numero di operazioni predefinite. L‟implementazione di una certa operazione può essere specificata in un linguaggio di programmazione general-purpose. www.ilparticolarenascosto.it Basi di dati 2 @ Unisa 9.5 9. Concetti sui database Object-Oriented Michele Nasti Gli utenti esterni dell'oggetto devono solo conoscere l'interfaccia dell'oggetto, che definisce nomi e argomenti di ciascuna operazione. L'implementazione è nascosta all'utente esterno: essa contiene la definizione delle strutture interne dell'oggetto e l'implementazione delle operazioni: – Interfaccia → Signature (o firma) – implementazione → Metodo . Un metodo è invocato mediante l'invio all'oggetto di un messaggio di eseguire il corrispondente metodo. L'esecuzione di un metodo può originare un successivo messaggio a un altro oggetto e così via. Tipicamente, l'esecuzione di un metodo avviene con la notazione punto: Esempio: D.no_of_emps determina l'invocazione del metodo no_of_emps sull'oggetto D. La richiesta di un completo incapsulamento è troppo stringente per applicazioni di database. Un modo di allentarla è di dividere la struttura di un oggetto in attributi visibili, accessibili in lettura a operatori esterni o al query language ad alto livello, e attributi nascosti, completamente incapsulati accessibili solo attraverso operazioni predefinite. Spesso le operazioni di update sono incapsulate, per definire la semantica delle modifiche sull'oggetto. Una classe è una definizione di un tipo di oggetto, insieme con le operazioni per quel tipo. Operazioni tipiche: – Costruttore di oggetto – Modificatori di oggetto – Recupero di informazioni relative all'oggetto Esempio. La classe Employee: attributi operazioni Non tutti gli oggetti sono permanenti nel database: gli oggetti transienti esistono durante l'esecuzione del programma e scompaiono con la terminazione del programma. Gli oggetti persistenti, memorizzati nel database, sopravvivono all‟esecuzione del programma. Esistono principalmente due meccanismi di persistenza: l'Assegnazione di un nome usato per ritrovare l'oggetto (naming), oppure rendere l'oggetto raggiungibile da altri oggetti persistenti (reachability). Con il meccanismo di naming si intende l'assegnamento di un nome univoco e persistente ad un oggetto, attraverso cui questo può essere referenziato da altri programmi. Gli oggetti con dei nomi rappresentano degli entry point attraverso cui si può accedere al db. Non è però possibile assegnare www.ilparticolarenascosto.it Basi di dati 2 @ Unisa 9.6 9. Concetti sui database Object-Oriented Michele Nasti nomi a tutti gli oggetti del db (che possono essere migliaia): la maggior parte degli oggetti sono resi persistenti col meccanismo di reachability. Il meccanismo di reachability funziona rendendo degli oggetti raggiungibili da oggetti persistenti. Un oggetto B è detto raggiungibile da un oggetto A se una sequenza di referenze nel grafo dell'oggetto porta da B ad A. Esempio. Illustrazione 2: La figura mostra tutti gli oggetti raggiungibili daO8. Se O8 è persistente, allora lo sono anche tutti gli altri oggetti presenti nella figura. Per creare collezioni persistenti usiamo un oggetto di nome N, il cui valore è una lista o un insieme di oggetti di una classe C. Gli oggetti di C sono resi persistenti aggiungendoli alla lista o insieme, e rendendoli quindi accessibili da N. Si dice che N definisce una collezione persistente di oggetti di classe C. www.ilparticolarenascosto.it Basi di dati 2 @ Unisa 9.7 9. Concetti sui database Object-Oriented Michele Nasti Esempio. Illustrazione 3: Definizione di una classe DepartmentSet contenente una collezione di oggetti Department. In un modello di DB tipico (ER, modello relazionale, ecc...) si assume che tutti gli oggetti siano persistenti. Quindi un tipo di entità quale EMPLOYEE, quando è definita, rappresenta la dichiarazione di tipo per EMPLOYEE e un insieme persistente di tutti gli oggetti EMPLOYEE. In un approccio O-O, una dichiarazione di classe di EMPLOYEE specifica solo il tipo e le operazioni per una classe di oggetti. L'utente deve separatamente definire un oggetto persistente di tipo set (EMPLOYEE) o list (EMPLOYEE), avente come valore una collezione di referenze a tutti gli oggetti persistenti EMPLOYEE. Per la stessa classe potrebbero essere definite più collezioni di oggetti persistenti. Assumiamo che per ogni definizione di classe, il nome della classe riferisca sia alle definizioni di tipo e di operazione che all'insieme di oggetti persistenti di quella classe. Gerarchie ed Ereditarietà nei DBMS O-O Nelle applicazioni di DB esistono numerosi oggetti dello stesso tipo. Ogni DBMS deve offrire la possibilità di classificare gli oggetti in funzione del loro tipo. Un OODBMS deve inoltre permettere la definizione di nuovi tipi a partire da altri predefiniti, giungendo ad una gerarchia di tipi. Un tipo viene definito assegnandogli un nome e definendo un certo numero di attributi e operazioni. Formato: TYPE_NAME: function, function, ... , function Esempio. PERSON: Name, Address, Birthdate, Age, SSN Name, Address, Birthdate e SSN sono implementati come attributi memorizzati. Age è implementato come metodo per il calcolo dell'età, in base al valore della data di nascita ed alla data corrente. Un sottotipo è utile per creare un nuovo tipo simile ma non identico a un tipo predefinito. Un sottotipo eredita tutte le funzioni del tipo predefinito, che viene detto supertipo. www.ilparticolarenascosto.it Basi di dati 2 @ Unisa 9.8 9. Concetti sui database Object-Oriented Michele Nasti Esempio. EMPLOYEE : Name, Address, Birthdate, Age, SSN, Salary, Hiredate, Seniority Possiamo dichiararlo come sottotipo di PERSON: EMPLOYEE subtype-of PERSON: Salary, Hiredate, Seniority Esempio. Dato il tipo: GEOMETRY_OBJECT: Shape, Area, ReferencePoint Shape è un attributo avente valori in {triangolo, rettangolo, cerchio, ecc ...}. Area è un metodo per il calcolo dell'area. Supponiamo di voler definire i sottotipi: – RECTANGLE subtype-of GEOMETRY_OBJECT: Width, Height – TRIANGLE subtype-of GEOMETRY_OBJECT: Side1, Side2, Angle – CIRCLE subtype-of GEOMETRY_OBJECT: Radius L'operazione Area di GEOMETRY_OBJECT può essere implementata in modo differente per ciascun sottotipo. L'attributo ReferencePoint può avere un significato differente per ciascun sottotipo; ad esempio centro per RECTANGLE e CIRCLE, vertice tra due lati per l'oggetto TRIANGLE, ecc ... Quando un oggetto viene creato, tipicamente può appartenere ad uno o più dei tipi dichiarati. Ad esempio:, un oggetto “CIRCLE” è sia di tipo CIRCLE che di tipo GEOMETRY_OBJECT, per ereditarietà. Alcuni sistemi O-O prevedono una superclasse di sistema predefinita (detta ROOT o OBJECT), da cui derivano tutti gli oggetti successivamente definiti. La classificazione procede specializzando oggetti nelle classi addizionali, creando una gerarchia di classe per il sistema. Nei DBMS O-O esiste una distinzione tra collezioni persistenti e collezioni transienti: una collezione persistente contiene oggetti memorizzati permanentemente nel db, e quindi accessibili da programmi esterni.; una collezione transiente esiste temporaneamente solo durante l'esecuzione di un programma. Oggetti Complessi Uno dei principali motivi che ha portato allo sviluppo di DBMS O-O è la necessità di rappresentare oggetti complessi. Gli oggetti complessi si dividono in strutturati e non strutturati . Il supporto di un DBMS ad oggetti complessi non strutturati (detti BLOBs, da Binary Large Objects) permette di gestire tipi di dati multimediali: immagini bit-map , stringhe di testo lunghe (documenti) , video , etc. Poiché i dati sono “non strutturati”, il DBMS non ne conosce la struttura, quindi solo l'applicazione che li utilizza può interpretarne il significato. Poiché un OODBMS consente agli utenti di creare nuovi tipi , e poiché un tipo include sia la struttura che le operazioni, possiamo vedere un OODBMS come avente un sistema di tipi estensibile; è quindi possibile creare librerie di tipi personalizzati. Negli oggetti complessi strutturati, la struttura è definita dalla ripetuta applicazione dei costruttori di tipo dell'OODBMS. La struttura dell'oggetto è quindi definita e conosciuta dal DBMS. www.ilparticolarenascosto.it Basi di dati 2 @ Unisa 9.9 9. Concetti sui database Object-Oriented Michele Nasti Concetti avanzati di Object-Orientation Il Polimorfismo (o overloading degli operatori) permette che lo stesso nome o simbolo sia legato a due o più diverse implementazioni dell'operatore, in base al tipo degli operandi. Il compilatore determina quale operazione applicare in base al tipo degli operandi. Esempio: GEOMETRY_OBJECT: Shape, Area, CenterPoint – RECTANGLE subtype-of GEOMETRY_OBJECT (Shape = „rectangle‟):Width, Height – TRIANGLE subtype-of GEOMETRY_OBJECT (Shape = „triangle‟): Side1, Side2, Angle – CIRCLE subtype-of GEOMETRY_OBJECT (Shape = „circle‟): Radius La funzione Area persiste per tutti gli oggetti rà una implementazione del metodo diversa per ogni sottotipo: area è overloaded da diverse implementazioni. www.ilparticolarenascosto.it Basi di dati 2 @ Unisa 9.10