Composició d'objectes

La composició d'objectes a les ciències de la computació és una manera de combinar objectes o tipus de dades simples per crear-ne un de més complex. Les composicions són una part important de moltes estructures de dades bàsiques (llista enllaçada, arbre binari…). S'usa principalment per implementar una relació entre dos objectes. La composició en general té una forta dependència del cicle de vida entre les instàncies de la classe contenidora i les instàncies de la classe continguda: si es destrueix el contenidor, normalment cada instància que conté es destrueix també.

Un exemple real de composició podria ser la relació entre un automòbil i les seves parts: un automòbil té o està compost per objectes com un volant, un seient, una caixa de canvis i un motor.

La composició s'ha de distingir del subtipatge, que és el procés de detallar un tipus de dada general o crear un tipus més específic. Per exemple, els cotxes poden ser un tipus específic de vehicle. El subtipatge no descriu una relació entre diferents objectes, sinó que mostra que un objecte d'un tipus és també a la vegada objecte d'un altre tipus.

Composició en UMLModifica

La representació gràfica d'una relació de composició en UML és una connexió entre les dues clases amb un diamant ple a l'extrem de la classe que conté l'altra classe, és a dir, la classe contenidora.

Diferencies entre composició i agregacióModifica

Un dubte que freqüentment ens podem plantejar a l'hora de modelar diagrames de classes, és l'ús de les relacions estructurals d'agregació i composició. Tant una com l'altra són tipus d'especialització de la relació d'associació entre classes. Veurem les diferències que existeixen entre la composició forta i la composició dèbil, coneguda habitualment com a agregació.

Agregació i diferènciesModifica

L'agregació és un tipus d'associació que indica que una classe és part d'una altra classe (composició dèbil). Els components de l'agregació poden ser compartits per diversos compostos (de la mateixa associació d'agregació o de diverses associacions d'agregació diferents) en canvi els components en al composició com a màxim només poden tenir un compost. La destrucció de l'objecte compost en l'agregació no comporta necessàriament la destrucció dels components, cosa que si passa amb la composició forta. Aquest tipus d'associació s'utilitza més sovint que la composició forta.

Vegem un exemple d'agregació: Una empresa té cap o molts clients i un client compra en 1 o moltes empreses, si una empresa és eliminada els seus clients podrà seguir existint i comprant en altres empreses. Que succeeix en canvi en la composició? Una empresa té un o molts empleats no pot existir per tant una empresa sense empleats. Un empleat només pot treballar en una empresa. Si una empresa és eliminada els empleats d'aquella empresa també hauran de ser eliminats.

En resum:

Text de capçalera Agregació Composició
Diverses associacions comparteixen els components Si No
Destrucció dels components al destruir el compost No Si
Cardinalitat a nivell de compost Qualsevol 0..1 o 1
Representació Rombe transparent Rombe negre

ImplementacióModifica

A nivell de codi la implementació tant de l'agregació com de la composició és molt senzilla i similar.

Normalment el que es fa és tenir un atribut (un objecte o bé una llista o vector d'objectes si tenim diversos components) en la classe contenidora on emmagatzemarem els objectes components i a més es declararà com a mínim un mètode en la classe per poder agregar aquest objectes a la col·lecció. En funció del llenguatge que utilitzem pot ser que usem una estructura de dades o una altra per emmagatzemar els compostos.

Vegem un exemple senzill en Java:

// Composció
public class Cotxe
{
 // un Cotxe disposarà de un Carburador.
 // El Carburador s'instanciarà juntament amb un Cotxe o no.
 // El cotxe s'instanciarà amb un carburador ja que
 // no hi pot haver un Cotxe sense carburador.
 // Si s'elimina el cotxe s'elimina el seu carburador i viceversa¡.
 private Carburador carb;
 public Cotxe(){
 this.carb=new Carburador();
 }
 public Cotxe(Carburador cb){
 this.carb=cb;
 }
}

// Agregació
public class Bassa
{
 //una Bassa pot tenir varis Anecs,
 //La bassa es podrà instanciar encara que no hi hagin ànecs.
 //Eliminar els ànecs no implica eliminar la bassa.
 private List<Anec> anecs;
 public Bassa(){
 anecs=new List<Anec>();
 }
 public void addAnec(Anec a){
 anecs.add(a);
 }
}

Evolució de la composició en diferents llenguatgesModifica

C anomena “struct” o “structure” a un registre; els llenguatges de programació orientats a objectes com Java, Smalltalk i C++ normalment amaguen els seus registres dins d'objectes (instàncies de classe); els llenguatges de la familia ML els anomenen simplement registres. COBOL va ser el primer llenguatge de programació que suportava registres directament, ALGOL 68 ho va obtindre de COBOL, i Pascal, més o menys indirectament, d'ALGOL 68. Commons Lisp proporciona estructures i classes (a través de Common Lisp Object System).

1959 – COBOL
01 customer-record.
 03 customer-number pic 9(8) comp.
 03 customer-name.
 05 given-names pic x(15).
 05 initial-2 pic x.
 05 surname pic x(15).
 03 customer-address.
 05 street.
 07 house-number pic 999 comp.
 07 street-name pic x(15).
 05 city pic x(10).
 05 country-code pic x(3).
 05 postcode pic x(8).
 03 amount-owing pic 9(8) comp.
1960 – ALGOL 60

Els Vectors són l'únic tipus de composició a Algol 60.

1964 – PL/I
dcl 1 newtypet based (P);
 2 (a, b, c) fixed bin(31),
 2 (i, j, k) float,
 2 r ptr;
allocate newtypet;
1968 – ALGOL 68
int max = 99;
mode newtypet = [0..9] [0..max]struct (
 long real a, b, c, short int i, j, k, ref real r
);
newtypet newarrayt = (1, 2, 3, 4, 5, 6, heap real := 7)

Aquí hi ha la declaració d'una llista enllaçada:

mode node = union (real, int, compl, string),
 list = struct (node val, ref list next);

Cal notar que a ALGOL 68 només el tipus apareix a la dreta de la igualtat, i que la construcció és feta –i pot ser llegida- de dreta a esquerra sense tenir en compte prioritats.

1970 – Pascal
type
 a = array [1..10] of integer;
 b = record
 a, b, c: real;
 i, j, k: integer;
 end;
1972 – K&R C
#define max 99
struct newtypet {
 double a, b, c;
 float r;
 short i, j, k;
} newarrayt[10] [max + 1];
1977 – FORTRAN 77

Fortran 77 té vectors, però manca qualsevol deficinió formal d'estructura. Normalment les estructures compostes eren construïdes mitjançant les paraules clau EQUIVALENCE o COMMON.

 CHARACTER NAME*32, ADDR*32, PHONE*16
 REAL OWING
 COMMON /CUST/NAME, ADDR, PHONE, OWING
1983 – ADA
type Cust is
 record
 Name : Name_Type;
 Addr : Addr_Type;
 Phone : Phone_Type;
 Owing : Integer range 1..999999;
 end record;
1983 – C++
const int max = 99;
class{
 public:
 double a, b, c;
 float &r;
 short i, j, k;
}newtypet[10] [max + 1];
1991 – Python
max = 99
class NewTypeT:
 def __init__(self):
 self.a = self.b = self.c = 0
 self.i = self.j = self.k = 0.0
# Initialise an example array of this class.
newarrayt = [[NewTypeT() for i in range(max + 1)] for j in range(10)]
1992 – FORTRAN 90

Arrays i strings van ser heretats de FORTRAN 77, i es va introduir una nova paraula reservada: type

type newtypet
 double precision a, b, c
 integer*2 i, j, k
* No pointer type REF REAL R
 end type

type (newtypet) t(10, 100)

FORTRAN 90 s'actualitza i inclou un concepte de FORTRAN IV anomenat NAMELIST.

INTEGER :: jan = 1, feb = 2, mar = 3, apr = 4
NAMELIST / week / jan, feb, mar, apr
1994 – ANSI Common Lisp

Common Lisp proporciona estructures i l'estandar ANSI Common Lisp va afegir classes CLOS.

(defclass some-class ()
 ((f :type float)
 (i :type integer)
 (a :type (array integer (10)))))

Enllaços externsModifica