torna al menù principale > linguaggio_c

Relazioni ta classi

La relazione stabilisce un legame tra le classi. (mentre i legami tra gli oggetti questi legami sono implementati con i collegamenti)

  • Ha il vantaggio di consentire un riutilizzo del codice delle classi.
  • Ha lo svantaggio di creare accoppiamento e dipendenza del codice delle classi.

Esistono diversi tipi di relazioni tra classi. Ogni tipo può essere descritto dalle seguenti caratteristiche:

  1. Ogni relazione possiede: un nome e (uno o più) versi di navigabilità
  2. Ogni classe coinvolta in una relazione può avere: un ruolo e una molteplicità

In questa tabella si utilizza la simbologia dello standard uml

relazione verbo verbo n.versi implementazione simbolo
composizione has a costituire 2 nested classes immagine
aggregazione has a costituire 1 oggetti membro immagine
associazione uses a utilizzare 1-2 ref./point. membro immagine
dipendenza uses a utilizzare 1 ?? immagine
generalizzazione is a essere 1 ereditarietà1 immagine
realizzazione is a essere 1 polimorfismo immagine

Fare esempi e confronti di relazioni tra classi (fatte bene e fatte male)

Nel linguaggio C++ le relazioni tra classi possono essere tradotte usando diverse tecniche di programmazione orientata agli oggetti:

  • una classe può essere definita dentro una classe (nested) (composizione)
  • una classe può essere definita fuori da una classe e instanziata dentro quella classe
    • come oggetto membro (aggregazione)
    • come puntatore o reference membro (associazione)
  • una classe può essere derivata a partire da un'altra classe (generalizzazione)

In questa ampia scelta, sono da privilegiare le relazioni più deboli perché sono più semplici e creano una minore dipendenza tra i moduli. Quale tra quelle citate è la relazione più debole e quale quella più forte? L'associazione? L'aggregazione?

Composizione

immagine

  • una linea continua con il simbolo del rombo pieno appoggiato alla classe contenitore
  • i numerini indicano la molteplicità
  • Ha sempre DUE versi di percorrenza (quindi due regole)
  • l'Aggregazione ha il simbolo del rombo vuoto.
  • La classe del componente può andar a comporre una sola classe contenitore
  • Non si possono creare nuovi oggetti senza creare prima il loro oggetto contenitore

Il verbo usato per descrivere questa relazione è has: possedere, avere, essere composto da… Nella Composizione le classi componenti esistono solo in relazione alla classe contenitore. Non si possono creare oggetti al di fuori di tali classi.

Poiché la relazione è forte è necessario dichiarare una classe nel namespace di una classe contenitore. In questo modo è realizzato anche il principio dell'esclusività.

Class A
{   
 private:    
    Class B
    {
    };
};

In questo modo tutte le funzioni membro della classe contenitore hanno accesso a tutti i dati membro dell'altra classe. Il costruttore della classe contenitore inizializzerà questi oggetti come inizializza gli altri oggetti. Se gli oggetti sono creati nello stack verranno inizializzati/distrutti automaticamente, mentre se puntato nell'heap dovrà occuparsene il costruttore/distruttore.

Se è necessario usare più volte questi oggetti (come 4 gambe di un tavolo) si possono usare vector.

Non confondere la molteplicità con il numero di versi di navigabilità. Se la molteplicità è uno si realizza aggiungendo dei puntatori nella classe contenitore. Se la molteplicità è maggiore di uno si implementa con i vettori

Codice sorgente con esempio di composizione

Creare le classi per disegnare punti e segmenti sul piano cartesiano. Lo stesso esempio può essere risolto:

  • con l'aggregazione se considero i punti pre-esistenti al segmento e quindi indipendenti.
  • con la composizione se considero di creare due nuovi punti per ogni segmento (non rappresento punti singoli)

Aggregazione

immagine

  • una linea continua con il simbolo del rombo vuoto vicino alla classe contenitore
  • i numerini indicano la molteplicità
  • Ha sempre UNO SOLO verso di percorrenza (quindi una regola)
  • la Composizione ha il simbolo del rombo pieno.

Il verbo usato per descrivere questa relazione è has: possedere, avere, essere composto da… Nell'Aggregazione le classi componenti esistono indipendentemente dalla classe contenitore

Possedere un oggetto significa avere un oggetto membro di quel tipo… Le classi componenti esistono indipendentemente dalla classe contenitore, quindi non è necessario definire tali classi all'interno dei contenitori, come lo è invece nella composizione. , perciò il distruttore del contenitore non si deve occupare della distruzione delle componenti. Se la molteplicità è uno si realizza aggiungendo dei reference nella classe contenitore. Se la molteplicità è maggiore di uno si implementa con array di puntatori o vector (i vector lavorano per copia)

class B
{
 //...
};

class A
{
   private:
        B m_b;
};

File sorgenti di un esempio di aggregazione

Creare le classi per disegnare punti e segmenti sul piano cartesiano. Lo stesso esempio può essere risolto:

  • con l'aggregazione se considero i punti pre-esistenti al segmento e quindi indipendenti.
  • con la composizione se considero di creare due nuovi punti per ogni segmento (non rappresento punti singoli)

Analisi del problema

  1. il segmento può essere creato a partire da punti pre-esistenti?
  2. cosa accade al punto se distruggo il segmento?(esclusività)
  3. cosa accade al segmento se distruggo un suo punto?
  4. un punto può appartenere a due segmenti contemporaneamente?(esclusività)

Associazione

immagine

  • La relazione di Associazione si rappresenta con una o due frecce su una linea continua.
  • L'Associazione ha un nome
  • I numerini indicano la molteplicità minima e massima (0..3, 1, *)
  • Le classi possono avere un ruolo
  • Può avere due versi di navigabilità (una o due frecce sulla linea), cioè DUE regole
  • La relazione di Dipendenza si rappresenta con la freccia a linea tratteggiata. (classi astratte???)

Il verbo usato per descrivere questa relazione è uses: utilizzare

Se A e B sono in relazione di associazione, allora le funzioni membro della classe A usano (usa) oggetti di tipo B. Questo si può tradurre in:

  1. avere funzioni che hanno come argomenti copie, puntatori o reference a oggetti di tipo B
  2. avere funzioni che restituiscono copie, puntatori o reference a oggetti di tipo B.
  3. avere membri di tipo reference o puntatori a oggetti di tipo B
Class B; // nell'interfaccia non serve la definizione completa di B...

Class A
{
   public:
           void fun(B& b);
};

A differenza della relazione di aggregazione, in quella di associazione il compilatore deve solo usare un indirizzo di memoria e nell'interfaccia della classe non deve conoscere necessariamente la dimensione dell'oggetto usato. Nel file sorgente che implementa la classe invece si deve conoscere anche la dimensione dell'oggetto usato…

Esempio di codice che fa uso dell'associazione

molti a molti

Sviluppare due classi che rappresentino il concetto di auto e di persona, nel senso che:

  • ogni persona possiede più auto
  • ogni auto appartiene a più persone

La presenza di DUE REGOLE indica un doppio orientamento: partendo da auto si può arrivare a persona e viceversa. contraddizione con precedente paragrafo???come si realizza????quando e' a uno si usa un puntatore alla classe vicina ???quando e' a molti si usa un vettore di puntatori

Tra due classi ci possono essere anche più relazioni (ad esempio l'auto può “appartenere” ma si può anche “guidare”). Può esistere lassociazione riflessiva??

Altro esempio molti a molti con i conti correnti e i correntisti… Il membro “saldo” è un dato “private” perché deve essere modificabile solo dalle funzioni membro del conto (come versamento o prelievo)

Classi associative

Se la relazione di associazione ha degli “attributi” si fa una linea tratteggiata perpendicolare a quella continua che rappresenta l'associazione e ci si attaccano gli attributi con una classe (detta appunto classe associativa) che ha lo stesso nome dell'associazione. Quella classe conterrà gli attributi dell'associazione. In realtà questo schema di due classi più una classe associativa, potrebbe essere realizzato in modo equivalente anche con tre classi “normali” e due associazioni (uno a molti?)

Uno a molti

  • ogni classe possiede uno o più studenti
  • ogni studente è contenuto in una classe

Generalizzazione

immagine

  • è quasi la stessa cosa dell'ereditarietà1, per approfondimento vedere libro “Usare UML”
  • ha il simbolo della linea continua che termina con un triangolo
  • ha UN SOLO verso e quindi una sola regola (vedi esempio)

Un oggetto della classe derivata implementa sia il modello della classe base che della classe derivata.

Si definisce la classe A come classe derivata dalla classe B , che è la classe base

Class B
{
  //etc.
};

class A : public B
{
  //etc.
};

In questo modo la classe A avrà, oltre ai propri membri, anche quelli ereditati da B.

Rispetto alla relazione di Aggregazione (o di Associazione), in questo caso, A può accedere ai membri dello stesso tipo di B senza aver bisogno di creare un oggetto di tipo B perché è lui stesso un oggetto di tipo B.

Questo può essere utile quando …?

immagine La relazione si riconosce quando nelle regole si può leggere: Ogni oggetto-derivato è un (is a) oggetto-base (non viceversa). Ogni automobile è un autoveicolo, Ogni camion è un autoveicolo, ecc…

Realizzazione

immagine

  • si rapprensenta con una linea tratteggiata che termina con un triangolo.

Si tratta di un caso particolare della generalizzazione (ereditarietà) in cui la classe base è una classe astratta (contiene cioè almeno una funzione membro virtuale pura).

Le classi astratte non vengono usate per instanziare oggetti ma per progettare un metodo di generazione del codice…

vedi esempio generalizzazione

in realtà non esistono oggetti autoveicoli che hanno una targa, un proprietario, ecc. Quindi questa classe è presente solo per poter creare più facilmente nuove classi come auto e camion. Per le regole di invocazione dei metodi vedere polimorfismo

  • appunti3s/relazioni_tra_classi.txt
  • Last modified: 2019/06/29 15:53
  • by profpro